嵌套事务和 EJBContext 的 setRollbackOnly()

Tap*_*ose 4 java jta java-ee-7 ejb-3.2 jakarta-ee

我正在阅读 Java EE 7 的事务管理,但对嵌套事务的概念和EJBContext#setRollbackOnly().

说我有两个会话bean,Bean1Impl并Bean2Impl和他们的签名是:

@Stateless 
@TransactionManagement(TransactionManagementType.CONTAINER)
public class Bean1Impl implements Bean1 {

    @Resource 
    private EJBContext context;

    @TransactionAttribute(REQUIRED)
    public void method1() {
        try {
            //some operations such as persist(), merge() or remove().
        }catch(Throwable th){
            context.setRollbackOnly();
        }
    }
}

@Stateless 
@TransactionManagement(TransactionManagementType.CONTAINER)
public class Bean2Impl implements Bean2 {

    @Resource 
    private EJBContext context;

    @TransactionAttribute(REQUIRED)
    public void method2() {
        try {
            //some operations such as persist(), merge() or remove().
            //an exception has been thrown
        }catch(Throwable th){
            context.setRollbackOnly();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如Java EE 7 教程中所述:

51.3.1.1 必需属性

如果客户端在事务中运行并调用企业 bean 的方法,则该方法在客户端的事务中执行。如果客户端未与事务关联,则容器在运行该方法之前启动一个新事务。

Required 属性是使用容器管理的事务划分运行的所有企业 bean 方法的隐式事务属性。除非您需要覆盖另一个事务属性,否则您通常不会设置 Required 属性。由于事务属性是声明性的,您可以在以后轻松更改它们。

在这种情况下,我不需要@TransactionAttribute(REQUIRED)在方法Bean1Impl#method1()和Bean2Impl#method2(). 我对吗?

所以在上面的代码中, 的事务Bean2Impl#method2()将在 的事务中运行Bean1Impl#method1()。

我可以将其视为嵌套事务吗?

如果Exception在方法内部抛出了一个Bean2Impl#method2(),最终会导致EJBContext.setRollbackOnly()从catch块中调用该方法,并且正如预期的那样,它应该回滚在try该方法的块内执行的操作。在这种情况下,交易以及Bean1Impl#method1(). 也会回滚吗?我的意思是:

如果有EJBContext.setRollbackOnly()来自Bean2Impl#method2()和的调用会发生什么

  • Bean2Impl#method2()Bean1Impl#method1()在任何数据库操作(如持久化、合并或删除)之前从方法中调用。
  • Bean2Impl#method2()Bean1Impl#method1()在任何数据库操作(如持久化、合并或删除)之后从方法中调用。

最后,如果该方法Bean2Impl#method2()成功执行但在成功返回后被EJBContext.setRollbackOnly()调用会发生什么?Bean1Impl#method1()Bean2Impl#method2()

Phi*_*all 5

这不是嵌套事务,JavaEE/JTA不支持嵌套事务。如果#method2()从它调用,则#method1()它在同一事务中运行。如果您想进行不同的交易,则需要#REQUIRES_NEW。EJBContext.setRollbackOnly()仅适用于当前事务。请注意,在调用事务资源上的所有操作(包括读取)后,有可能EJBContext.setRollbackOnly()会抛出异常(JBoss AS 5.1 这样做了,不知道当前的行为)。

更新:

    }catch(Throwable th){
        context.setRollbackOnly();
    }
Run Code Online (Sandbox Code Playgroud)

对于运行时异常,您不需要它,这是 EJB 的默认行为。


kos*_*tja 5

添加到@Philippe Marshall 的正确答案和您的评论中 -REQUIRES_NEW将创建一个独立于第一个事务的新事务。它们不是嵌套的。第一个事务暂停,而第二个事务处于活动状态。一旦第二个事务提交,第一个事务就会恢复。

您不必setRollbackOnly()手动。PersistenceException如果需要,大多数人会这样做。通过回滚不需要的事务,您将一无所获。例如,在查询数据时,您可能会得到 aNoResultException或 a NonUniqueResultException。它们不会导致事务回滚,因为持久性上下文和数据库之间不存在不一致的风险。

您不需要指定两者都不@TransactionAttribute(REQUIRED)是@TransactionManagement(TransactionManagementType.CONTAINER)- 两者都是默认设置。

编辑:回答您的进一步问题:

我假设@TransactionAttribute(REQUIRES_NEW)的method2,因此两个独立的交易。

如果在 中存在Exception导致事务回滚的method2,则method1如果捕获到异常,则不会回滚来自 的事务。如果Exception没有被捕获,两个事务都将被回滚。

在事务上设置回滚标志时,它发生在数据库操作之前还是之后都没有关系,因为整个事务都被回滚了。

一旦method2返回,它的事务就被提交。之后回滚或提交事务method1对第一个事务的结果没有影响。

一般建议 - 不要捕捉Throwable- 它太宽泛了,您可能会吞下您宁愿让其传播到表面的异常。