Hibernate 休眠:session.get和session.load之间的差异

Hibernate 休眠:session.get和session.load之间的差异,hibernate,proxy,hibernate-session,Hibernate,Proxy,Hibernate Session,从API中,我可以看出它与代理有关。但是我找不到关于代理的很多信息,也不理解调用session.get和session.load之间的区别。有人能给我解释一下或者给我一个参考页吗 谢谢 来自: 这本书来自《冬眠行动》。好的,读这个 按标识符检索对象 以下Hibernate代码段从数据库检索用户对象: User user = (User) session.get(User.class, userID); get()方法是特殊的,因为标识符唯一地标识单个 类的实例。因此,应用程序通常使用标识符作

从API中,我可以看出它与代理有关。但是我找不到关于代理的很多信息,也不理解调用
session.get
session.load
之间的区别。有人能给我解释一下或者给我一个参考页吗

谢谢

来自:

这本书来自《冬眠行动》。好的,读这个


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

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

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

如果load()在缓存或数据库中找不到对象,则会出现异常 扔。load()方法从不返回null。get()方法返回 如果找不到对象,则为null

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

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

把它想象成一个只保留Id的对象,如果需要,它将加载其余的Id。如果只是为了创建关系(如FKs)而传递它,那么id就是您所需要的全部。

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

session.get()始终命中数据库并返回真实对象,即表示数据库行的对象,而不是代理。 如果未找到行,则返回null


这些方法的性能也会造成差异。在两个…

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

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

这里尝试用两个会话来描绘这个场景,两个会话处理具有相同标识符的对象。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,并且版本号将在正确的时间加载以进行乐观锁检查。

还有一点:

若在缓存和数据库中都找不到对象,Hibernate会话类的get方法将返回null。
如果在缓存和数据库中都找不到对象,则load()方法会抛出ObjectNotFoundException,但不会返回null。


session.load():
它总是返回一个“代理”(Hibernate术语),而不会命中数据库。
在Hibernate中,代理是一个具有给定标识符值的对象,其属性尚未初始化,只是看起来像一个临时的假对象。
它将始终返回具有给定标识值的代理对象,即使该标识值在数据库中不存在。但是,当您试图通过从数据库检索代理的属性来初始化代理时,它将使用select语句命中数据库。如果找不到行,将抛出ObjectNotFoundException。
session.get():
它总是命中数据库(如果在缓存中找不到),并返回真实对象,即表示数据库行的对象,而不是代理。
如果未找到行,则返回null。
load()无法从缓存或数据库中找到对象,将引发异常,load()方法从不返回null

如果找不到对象,get()方法将返回null。load()方法可能返回一个代理,而不是真正的持久实例get()
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]