我在包含多个模块的项目中使用EJB3和JPA2。 最近我注意到DB-records在异常时不会回滚。在做了一些研究之后,我发现实体管理器甚至在方法结束之前就立即在事务上提交了事务,这样它就无法在异常时回滚。
我使用
注入实体经理SELECT cost*0.9 AS discounted_cost FROM products;
创建一个新记录是持久的,并在同一个类中调用flush vering
@PersistenceContext
private EntityManager entityManager;
即使我在刷新后立即调用new new RuntimException(""),它也不会回滚。在调用flush之后的调试中,我可以在方法结束之前使用数据库工具选择DB记录。
我已经检查过persistence.xml,但没有发现异常。我不使用任何其他规范配置。 我想出了可能导致这种行为的想法。我批评任何线索。
答案 0 :(得分:0)
您需要指定事务边界,否则将在每次数据操作查询(INSERT,UPDATE,DELETE)之后打开并提交新事务。由于em.flush()
将触发此类SQL查询执行,它将打开一个隐式事务并在SQL成功时提交它,如果出错则回滚。
为了设置事务边界并使RuntimeException触发回滚,最好的选择是从EJB对象调用entityManager方法。您必须使用 JTA数据源,而不是RESOURCE_LOCAL。如果您不使用JTA数据源,则需要自己管理事务,即。通过使用entityManager.getTransaction()对象。
在EJB之外,或者在非JTA数据源之外,您没有打开任何事务,除非您通过调用entityManager.getTransaction()。begin()来自己启动它。但是,通过这种方式,抛出Exception时将不会回滚您的事务。相反,您必须在catch块中回滚。在Java SE应用程序中,这主要位于Java EE容器之外。在Java EE中,我强烈建议使用JTA数据源。例如:
public class NotAnEJB {
public persistEntity(EntityManager em, MyEntity entity) {
em.getTransaction().begin();
try {
em.persist(entity);
em.flush();
if (shouldFail()) {
throw new RuntimeException();
}
em.commit();
} catch (Exception e) {
em.rollback();
}
}
}