4

我正在阅读 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();
        }
    }
}

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()fromBean2Impl#method2()和会发生什么

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

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

4

2 回答 2

5

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

更新:

    }catch(Throwable th){
        context.setRollbackOnly();
    }

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

于 2013-12-29T11:39:38.670 回答
5

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

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

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

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

我假设两个单独@TransactionAttribute(REQUIRES_NEW)method2交易。

如果 中存在Exception导致事务回滚的情况,则如果捕获到 Exception method2,则事务 frommethod1将不会回滚。如果Exception没有被捕获,两个事务都将被回滚。

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

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

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

于 2013-12-29T12:38:05.533 回答