从 API 中,我可以看到它与代理有关。但是我找不到很多关于代理的信息,也不明白调用session.get
和之间的区别session.load
。有人可以解释或指导我到参考页面吗?
谢谢!!
从 API 中,我可以看到它与代理有关。但是我找不到很多关于代理的信息,也不明白调用session.get
和之间的区别session.load
。有人可以解释或指导我到参考页面吗?
谢谢!!
从休眠论坛:
这来自《休眠在行动》一书中。很好读这个..
按标识符检索对象 以下 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() 在缓存或数据库中找不到持久对象时可能不会抛出异常;当访问代理时,稍后将引发异常。当然,通过标识符检索对象不如使用任意查询灵活。
好吧,至少在 nhibernate 中, session.Get(id) 将从数据库中加载对象,而 session.Load(id) 仅在不离开服务器的情况下为其创建代理对象。就像您的 POCO(或 POJO :) 中的所有其他延迟加载属性一样工作。然后,您可以使用此代理作为对对象本身的引用来创建关系等。
把它想象成有一个只保留 Id 的对象,如果你需要它会加载其余的。如果您只是传递它来创建关系(如 FK),那么 id 就是您所需要的。
session.load() 将始终返回“代理”(Hibernate 术语)而不会访问数据库。在 Hibernate 中,代理是一个具有给定标识符值的对象,它的属性还没有初始化,它只是看起来像一个临时的假对象。如果未找到任何行,则会抛出 ObjectNotFoundException。
session.get() 总是命中数据库并返回真实对象,一个代表数据库行的对象,而不是代理。如果没有找到行,则返回 null。
这些方法的性能也会产生差异。两...
还有一个额外的点::
如果在缓存和数据库中都没有找到对象,则 Hibernate Session 类的 get 方法返回 null。while load() 方法抛出 ObjectNotFoundException 如果在缓存和数据库上都没有找到对象,但从不返回 null。
使用“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 将立即发出一个选择,并且版本号将在正确的时间加载以进行乐观锁检查。
此外,在使用 load 时我们必须小心,因为如果对象不存在,它将引发异常。只有当我们确定该对象存在时,我们才必须使用它。
在http://www.mkyong.com/hibernate/differ-between-session-get-and-session-load
session.load()找到了一个很好的解释:
它总是会返回一个“代理”(Hibernate 术语)而不击中数据库。
在 Hibernate 中,代理是一个具有给定标识符值的对象,它的属性还没有初始化,它只是看起来像一个临时的假对象。
它将始终返回具有给定标识值的代理对象,即使该标识值在数据库中不存在。但是,当您尝试通过从数据库中检索代理的属性来初始化代理时,它将使用 select 语句访问数据库。如果没有找到行,将抛出 ObjectNotFoundException。
session.get() :
它总是命中数据库(如果在缓存中没有找到)并返回真实对象,一个代表数据库行的对象,而不是代理。
如果没有找到行,则返回 null。
load() 无法从缓存或数据库中找到对象,抛出异常并且 load() 方法永远不会返回 null。
如果找不到对象,get() 方法返回 null。load() 方法可能返回一个代理而不是一个真正的持久实例 get() 永远不会返回一个代理。