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