休眠:session.get 和 session.load 之间的区别

Posted

技术标签:

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

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

谢谢!!

【问题讨论】:

【参考方案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。

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

【讨论】:

与mkyong.com/hibernate/… 的措辞相同(但我不知道谁是第一个)【参考方案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() 永远不会返回一个代理。

【讨论】:

以上是关于休眠:session.get 和 session.load 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

休眠一个 isession 相同的 idbconnection

Session.get() 和 EntityManager.find() Hibernate 有啥区别

Hibernate session.createCriteria 与 session.get 性能

cookie和session

(sqlite,Flask + React),flask session session.get() 返回 None [重复]

Hibernate中Session.get()方法和load()方法的详细比较