ChatGPT解决这个技术问题 Extra ChatGPT

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

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

谢谢!!


N
Nandkumar Tekale

Hibernate forum

这来自《休眠在行动》一书中。很好读这个..

按标识符检索对象 以下 Hibernate 代码片段从数据库中检索用户对象:

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。如果该代理在会话中,他们为什么要检索代理而不是真实实例?
J
Jorge Alves

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

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


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

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

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

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


mkyong.com/hibernate/… 上的措辞相同(但我不知道谁是第一个)
m
madhu_karnati

还有一个额外的点::

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


S
SteveT

使用“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 将立即发出一个选择,并且版本号将在正确的时间加载以进行乐观锁检查。


S
Sanjay

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


b
black jack

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


Y
Yasser Shaikh

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

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