我最近遇到了一个有趣的问题。我在项目JPA + Hibernate + EJB中使用。该问题涉及在同一事务中保存和删除实体。使用的数据库表具有在两列上定义的唯一约束。
我所做的是删除实体调用
entityManager.remove();
然后在与唯一约束中使用的列关联的两个属性中添加相同值的新实体,但使用其他属性中的值不同:
entityManager.persist();
这两项操作在一次交易中执行,并按上述顺序执行。首先去除,再加上第二个。但是,当违反唯一约束时,操作似乎以反转顺序执行。看起来在删除前一个实体之前添加了新实体。
显然,我可以打电话
entityManager.flush()
删除后然后不违反约束。但是,在这种情况下,数据在整个事务提交之前保存到数据库中。这不是一个理想的行为。如果在刷新之后出现任何问题,并且事务将被标记为回滚,则无论如何都将删除该实体。
我认为操作顺序与添加到事务中的操作顺序相同。从我的例子可以看出它不是。
在删除后没有刷新或提交事务有没有办法解决问题?
谢谢。
答案 0 :(得分:5)
显然,我可以致电
entityManager.flush()
其实你必须打电话给它。
但是在这种情况下,数据会在之前保存到数据库中 整个交易提交。
这是错误的:数据已同步到数据库,但事务仍未提交,除非您手动提交并控制数据库。如果您没有在EJB中配置任何内容,并且您的持久性单元是JTA(请参阅this question with comments),那么只有在方法从EJB层返回后才会提交事务。
我认为操作顺序与添加它们的顺序相同 交易。从我的例子可以看出它不是。
不,JPA规范不强制实现这样做。这就是flush()
操作的原因。
有没有办法解决这个问题,而无需刷新或提交 删除后的交易?
是的,正如我所说的那样使用flush()
。还要确保使用事务数据库引擎(例如,MySql中的MyIsam不支持事务)。
答案 1 :(得分:2)
不建议使用Ossama Nasser建议的解决方案,因为如果某些内容在第二次或下一次交易中失败,使用不同的交易会使回滚到初始状态的可能性无效。
entityManager.flush()是正确的解决方案。
答案 2 :(得分:0)
我确实遇到了同样的问题,我解决了这个问题:
EntityManager.getTransaction().begin();
EntityManager.remove();
EntityManager.persist();
EntityManager.getTransaction().commit();
如果出现任何问题,请将删除和持久操作转换为两个不同的事务