休眠: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.get
和session.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好吧,至少在 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 性能
(sqlite,Flask + React),flask session session.get() 返回 None [重复]