为了账号安全,请及时绑定邮箱和手机立即绑定

在Hibernate中重新附加分离对象的正确方法是什么?

/ 猿问

在Hibernate中重新附加分离对象的正确方法是什么?

吃鸡游戏 2019-10-15 10:04:05

我遇到一种情况,我需要将分离的对象重新附加到休眠会话,尽管会话中可能已经存在相同标识的对象,这将导致错误。

现在,我可以做两件事之一。

  1. getHibernateTemplate().update( obj ) 当且仅当休眠会话中不存在对象时,此方法才有效。当以后需要时,会抛出异常,说明会话中已经存在具有给定标识符的对象。

  2. getHibernateTemplate().merge( obj ) 仅当休眠会话中存在对象时,此方法才有效。如果我以后使用该对象,则当我需要该对象进入会话时,将引发异常。

在这两种情况下,如何将会话附加到对象上?我不想使用异常来控制此问题的解决方案的流程,因为必须有一个更优雅的解决方案...


查看完整描述

3 回答

?
aluckdog

因此,似乎没有办法在JPA中重新附加陈旧的独立实体。


merge() 会将过时的状态推送到数据库,并覆盖所有中间更新。


refresh() 不能在独立实体上调用。


lock() 无法在分离的实体上调用,即使可以,它也确实重新连接了实体,并使用参数LockMode.NONE调用“ lock”,这意味着您正在锁定而不是锁定是API设计中最违反直觉的部分我见过的。


所以你被困住了。有一种detach()方法,但是没有attach()或reattach()。您无法使用对象生命周期中明显的步骤。


从有关JPA的类似问题的数量来看,即使JPA确实声称拥有一个连贯的模型,但它肯定与大多数程序员的思维模型不符,大多数程序员被诅咒浪费了很多时间试图理解如何获得知识。 JPA做最简单的事情,最终在整个应用程序中得到缓存管理代码。


似乎唯一的方法是丢弃陈旧的分离实体并执行具有相同ID的查找查询,这将影响L2或DB。


米克


查看完整回答
反对 回复 2019-10-15
?
慕莱坞7535251

所有这些答案都没有一个重要的区别。update()用于将对象图(重新)附加到会话。您传递给它的对象就是被管理的对象。


merge()实际上不是(重新)附加API。请注意merge()是否有返回值?那是因为它返回给您托管图,它可能不是您传递给它的图。merge()是JPA API,其行为受JPA规范支配。如果您传递给merge()的对象已经被管理(已经与Session关联),那么Hibernate就可以使用该图;传入的对象与从merge()返回的对象相同。但是,如果传递给merge()的对象是分离的,则Hibernate将创建一个受管理的新对象图,并将其状态从分离的图复制到新的托管图上。同样,这全部由JPA规范规定和支配。


就“确保管理此实体,或使其得到管理”的通用策略而言,它取决于您是否还要考虑尚未插入的数据。假设您这样做,请使用类似


if ( session.contains( myEntity ) ) {

    // nothing to do... myEntity is already associated with the session

}

else {

    session.saveOrUpdate( myEntity );

}

注意,我使用了saveOrUpdate()而不是update()。如果您不想在这里处理尚未插入的数据,请改用update()。


查看完整回答
反对 回复 2019-10-15
?
互换的青春

如果您确定您的实体尚未被修改(或者如果您同意任何修改将丢失),则可以使用锁定将其重新连接到会话。


session.lock(entity, LockMode.NONE);

它不会锁定任何内容,但是会从会话缓存中获取实体,或者(如果未在其中找到)从数据库读取实体。


当您从“旧”(例如HttpSession)实体导航关系时,防止LazyInitException非常有用。您首先要“重新附加”实体。


使用get也可能会起作用,除非您继承映射时(继承已在getId()上引发异常)。


entity = session.get(entity.getClass(), entity.getId());


查看完整回答
反对 回复 2019-10-15

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信