Hibernate @PreRemove在独立事务中无法正常工作的问题求助
Hibernate @PreRemove跨会话删除无法更新关联Allocation的server_id问题解决
问题原因
跨会话删除时,从第一个会话获取的Server对象在事务提交后会变成游离状态(detached),其关联的Allocation对象也会处于游离状态。当在新会话中执行session.remove(server)时,Hibernate会将Server重新关联到当前会话,但关联的Allocation仍然是游离的——Hibernate不会自动跟踪游离对象的修改,所以@PreRemove中调用allocation.setServer(null)的变更不会同步到数据库。
解决方案
方案1:在@PreRemove中手动关联游离的Allocation到当前会话
修改Server类的@PreRemove方法,通过当前会话将游离的Allocation实例重新关联,确保修改能被Hibernate跟踪:
@Entity @Table(name = "servers") @Getter @Setter public class Server { // 省略其他字段... @Autowired private transient SessionFactory sessionFactory; @PreRemove private void preRemove() { Session currentSession = sessionFactory.getCurrentSession(); for (Allocation allocation : allocations) { // 将游离对象合并到当前会话,得到受管理的实例 Allocation managedAllocation = currentSession.merge(allocation); managedAllocation.setServer(null); } setAllocations(null); } }
方案2:通过级联配置自动处理关联对象
在Server的@OneToMany注解中添加cascade = CascadeType.MERGE,这样当Server被合并到新会话时,关联的Allocation也会自动被合并:
@OneToMany(mappedBy = "server", fetch = FetchType.EAGER, cascade = CascadeType.MERGE) private List<Allocation> allocations;
然后在删除时先将游离的Server合并到当前会话,再执行删除:
Session session1 = sessionFactory.getCurrentSession(); session1.beginTransaction(); // 合并游离的Server到当前会话,关联的Allocation会被同步管理 Server managedServer = session1.merge(server); session1.remove(managedServer); session1.getTransaction().commit();
方案3:删除前重新加载Server(已知方案补充说明)
在删除会话中重新查询Server实例,此时Server和关联的Allocation都处于当前会话的管理下,@PreRemove中的修改会自动同步到数据库:
Session session1 = sessionFactory.getCurrentSession(); session1.beginTransaction(); Server managedServer = session1.createQuery("from Server where id = :id", Server.class) .setParameter("id", server.getId()) .getSingleResult(); session1.remove(managedServer); session1.getTransaction().commit();
方案对比
- 方案1:对业务代码侵入小,无需修改删除逻辑,但依赖
SessionFactory,且merge会触发额外查询 - 方案2:通过映射配置简化业务逻辑,删除时只需合并再删除,适合需要复用
Server对象的场景 - 方案3:逻辑简单直观,但需要额外查询一次
Server,适合场景简单的情况
内容的提问来源于stack exchange,提问作者OpenSource
相关产品推荐
相关产品推荐

