【问题标题】:Hibernate: Difference between session.get and session.load休眠:session.get 和 session.load 之间的区别
【发布时间】:2010-10-11 04:07:18
【问题描述】:

从 API 中,我可以看出它与代理有关。但是我找不到很多关于代理的信息,也不明白调用session.getsession.load 之间的区别。有人可以解释一下或将我引导到参考页面吗?

谢谢!!

【问题讨论】:

    标签: hibernate proxy hibernate-session


    【解决方案1】:

    来自Hibernate forum

    这来自 Hibernate in Action 一书。好人读了这个..


    通过标识符检索对象 下面的 Hibernate 代码 sn -p 从数据库中检索一个 User 对象:

    User user = (User) session.get(User.class, userID);
    

    get() 方法比较特殊,因为标识符唯一标识一个 类的实例。因此,应用程序通常将标识符用作 持久对象的方便句柄。按标识符检索可以使用缓存 检索对象时,如果对象已被缓存,则避免数据库命中。 Hibernate 还提供了一个 load() 方法:

    User user = (User) session.load(User.class, userID);
    

    load() 方法较旧;由于用户原因,get() 被添加到 Hibernate 的 API 要求。差别不大:

    如果 load() 无法在缓存或数据库中找到对象,则异常是 抛出。 load() 方法永远不会返回 null。 get() 方法返回 如果找不到对象,则返回 null。

    load() 方法可能返回一个代理而不是一个真正的持久实例。 代理是一个占位符,当它被加载时触发真实对象的加载 首次访问;在 另一方面, get() 从不返回代理。 在 get() 和 load() 之间进行选择很容易:如果您确定持久性 对象存在,不存在将被视为异常, load() 是 不错的选择。如果您不确定是否存在具有给定的持久实例 标识符,使用 get() 并测试返回值是否为空。使用 load() 有 进一步的含义:应用程序可以检索到一个有效的引用(代理) 持久化实例,而无需访问数据库以检索其持久状态。所以 load() 在找不到持久对象时可能不会抛出异常 在缓存或数据库中;稍后会抛出异常,当代理 被访问。 当然,通过标识符检索对象不如使用任意 查询。

    【讨论】:

    • 我现在正在调试 session.Get() 返回代理的问题!
    • 非常感谢!对我来说,钱的部分是:“如果 load() 在缓存或数据库中找不到对象,则会引发异常。如果找不到对象,get() 方法将返回 null。”
    • Session.get 的 JavaDoc 说:返回具有给定标识符的给定实体类的持久实例,如果没有这样的持久实例,则返回 null。 (如果实例或实例的代理已经与会话相关联,则返回该实例或代理。)因此书中的部分说:“另一方面,get() 永远不会返回代理。”不正确。
    • 如果你在你的 daos 中使用事务管理策略,你可能更喜欢 get()。否则调用者还需要在打开的休眠会话的上下文中执行,以防 load() 返回代理。例如,如果您正在执行 MVC,您的控制器可能会执行 dao.load(),然后如果没有有效会话,稍后在尝试访问代理对象时会抛出异常。执行 dao.get() 会将实际对象返回给控制器,而不管会话如何(假设它存在)
    • @Vicky 描述的问题可能会让人头疼,我看不出它有什么好处。在某些情况下,我还需要标识符来进行进一步的参数化查询。但是由于对象的代理已经在会话中,标识符的getter返回null。如果代理在会话中,他们为什么要检索代理而不是真实实例?
    【解决方案2】:

    好吧,至少在 nhibernate 中, session.Get(id) 将从数据库中加载对象,而 session.Load(id) 仅在不离开服务器的情况下为其创建代理对象。就像您的 POCO(或 POJO :) 中的所有其他延迟加载属性一样工作。然后,您可以使用此代理作为对对象本身的引用来创建关系等。

    把它想象成有一个只保留 Id 的对象,如果你需要它会加载其余部分。如果您只是传递它来创建关系(如 FK),那么 id 就是您所需要的。

    【讨论】:

    • 所以你想说 load(id) 将首先访问数据库以检查它是否是有效的 id,然后将返回代理对象,当访问该对象的属性时它会命中又是数据库?这不是一个不太可能的情况吗?加载单个对象的两个查询?
    • 不,load(id) 根本不会验证 id,因此不会往返于数据库。仅当您确定它有效时才使用它。
    【解决方案3】:

    session.load() 将始终返回一个“代理”(Hibernate 术语)而不会访问数据库。在 Hibernate 中,代理是一个具有给定标识符值的对象,它的属性还没有初始化,它只是看起来像一个临时的假对象。 如果未找到任何行,则会抛出 ObjectNotFoundException。

    session.get() 总是访问数据库并返回真实对象,一个代表数据库行的对象,而不是代理。 如果没有找到行,则返回 null。

    这些方法的性能也会产生差异。两个...

    【讨论】:

    【解决方案4】:

    还有一点加分::

    如果在缓存和数据库中都没有找到对象,则 Hibernate Session 类的 get 方法返回 null。 while load() 方法抛出 ObjectNotFoundException 如果在缓存和数据库中都没有找到对象,但从不返回 null。

    【讨论】:

      【解决方案5】:

      使用“load”而不是“get”的一个间接后果是,使用版本属性的乐观锁定可能不会像您期望的那样工作。如果加载只是创建一个代理而不从数据库中读取,则不会加载版本属性。只有当/如果您稍后引用对象上的属性,触发选择时,才会加载该版本。同时,另一个会话可以更新对象,并且您的会话将没有执行乐观锁检查所需的原始版本 - 因此您的会话的更新将覆盖另一个会话的更新,而不会发出警告。

      这里试图用两个会话处理具有相同标识符的对象来勾勒这个场景。 DB 中对象的初始版本是 10。

      Session 1                  Session 2
      ---------                  ---------
      Load object
      Wait a while..   
                                 Load object
                                 Modify object property
                                 [triggers db 'select' -
                                  version read as 10]
                                 Commit
                                 [triggers db update,
                                  version modified to 11]
      Modify object property
        [triggers db 'select' -
        version read as 11]
      Commit
        [triggers db update,
        version modified to 12]
      

      我们实际上希望会话 1 的提交因乐观锁定异常而失败,但在这里它会成功。

      使用“get”而不是“load”可以解决该问题,因为 get 会立即发出一个 select,并且版本号将在正确的时间加载以进行乐观锁检查。

      【讨论】:

        【解决方案6】:

        此外,我们在使用 load 时必须小心,因为如果对象不存在,它会抛出异常。只有当我们确定该对象存在时,我们才必须使用它。

        【讨论】:

          【解决方案7】:

          http://www.mkyong.com/hibernate/different-between-session-get-and-session-load 找到了一个很好的解释
          session.load() :
          它总是会返回一个“代理”(Hibernate 术语)而不访问数据库。
          在 Hibernate 中,代理是一个具有给定标识符值的对象,它的属性还没有初始化,它看起来就像一个临时的假对象。 它将始终返回具有给定标识值的代理对象,即使该标识值在数据库中不存在。但是,当您尝试通过从数据库中检索代理的属性来初始化代理时,它将使用 select 语句访问数据库。如果未找到任何行,则会抛出 ObjectNotFoundException。
          session.get() :
          它总是命中数据库(如果在缓存中没有找到)并返回真实对象,一个代表数据库行的对象,而不是代理。
          如果没有找到行,则返回 null。

          【讨论】:

            【解决方案8】:

            load() 无法从缓存或数据库中找到对象,抛出异常并且 load() 方法永远不会返回 null。

            如果找不到对象,

            get() 方法返回 null。 load() 方法可能返回一个代理而不是一个真正的持久实例 get() 永远不会返回一个代理。

            【讨论】:

              猜你喜欢
              • 2018-02-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-07-09
              • 1970-01-01
              • 2013-07-10
              相关资源
              最近更新 更多