Java 嵌套事务和 EJBContext 的 setRollbackOnly()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20823798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 04:37:03  来源:igfitidea点击:

Nested Transaction and EJBContext's setRollbackOnly()

javajakarta-eejtajava-ee-7ejb-3.2

提问by Tapas Bose

I am reading the Transaction Management of Java EE 7 and I get confused by the concept of nested transaction and the functionality of EJBContext#setRollbackOnly().

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

Say I have two Session Beans, Bean1Impland Bean2Impland their signatures are:

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

@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();
        }
    }
}

As stated in Java EE 7 Tutorial:

正如Java EE 7 教程中所述

51.3.1.1 Required Attribute

If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method.

The Required attribute is the implicit transaction attribute for all enterprise bean methods running with container-managed transaction demarcation. You typically do not set the Required attribute unless you need to override another transaction attribute. Because transaction attributes are declarative, you can easily change them later.

51.3.1.1 必需属性

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

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

In this case I don't need to specify @TransactionAttribute(REQUIRED)annotation declaration in the methods Bean1Impl#method1()and Bean2Impl#method2(). Am I right?

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

So in the above code the transaction of Bean2Impl#method2()would be running within the transaction of Bean1Impl#method1().

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

Can I consider it as a Nested Transaction?

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

If there is an Exceptionhas been thrown inside the method Bean2Impl#method2()which eventually would lead to a call to the method EJBContext.setRollbackOnly()from the catchblock and as expected it should roll back the operations performed within the tryblock of this method. In this case what would happen to the transaction and as well as the Bean1Impl#method1(). Would it be rolled back as well? What I mean is:

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

What would happen if there is a call of EJBContext.setRollbackOnly()from Bean2Impl#method2()and

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

  • Bean2Impl#method2()is called from the method Bean1Impl#method1()before any database operation like persist, merge or remove.
  • Bean2Impl#method2()is called from the method Bean1Impl#method1()after any database operation like persist, merge or remove.
  • Bean2Impl#method2()Bean1Impl#method1()在任何数据库操作(如持久化、合并或删除)之前从方法中调用。
  • Bean2Impl#method2()Bean1Impl#method1()在任何数据库操作(如持久化、合并或删除)之后从方法中调用。

And lastly what would happen if the method Bean2Impl#method2()get executed successfully but EJBContext.setRollbackOnly()is called from Bean1Impl#method1()after successful return of Bean2Impl#method2()?

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

采纳答案by kostja

To add to @Philippe Marshall's correct answer and your comment - REQUIRES_NEWwill create a new transaction, independent from the first one. They are not nested. The first transaction is suspended while the second is active. Once the second transaction commits, the first one is resumed.

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

You do not have to setRollbackOnly()manually. Most PersistenceExceptions will do that if needed. You will gain nothing by rolling back transactions that you don't have to. For example, when querying data, you may get a NoResultExceptionor a NonUniqueResultException. They do not cause a transaction to be rolled back as there is no risk of inconsistencies between the persistence context and the DB.

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

You do not need to specify neither @TransactionAttribute(REQUIRED)nor @TransactionManagement(TransactionManagementType.CONTAINER)- both are the default settings.

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

EDIT: to answer your further questions:

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

I am assuming @TransactionAttribute(REQUIRES_NEW)on method2and therefore two separate transactions.

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

If there is an Exceptionthat leads to the rollback of the transaction in method2, the transaction from method1will not be rolled back if the Exception is caught. If the Exceptionis not caught, both transactions will be rolled back.

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

When setting the rollback flag on a transaction, it does not matter whether it happens before or after DB operations, since the entire transaction is rolled back.

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

Once method2returns, it's transaction is committed. Rolling back or committing the transaction from method1afterwards has no influence on the results of the first transaction.

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

A general advice - do not catch Throwable- it is much too broad and you might swallow exceptions which you would rather let propagate to the surface.

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

回答by Philippe Marschall

This is not nested transactions, JavaEE / JTA does not support nested transaction. If #method2()is called from #method1()it runs in the same transaction. If you want to have a different transaction you need #REQUIRES_NEW. EJBContext.setRollbackOnly()only works on the current transaction. Note there is a chance that after calling EJBContext.setRollbackOnly()all operations on the transactional resource including reads will throw an exception (JBoss AS 5.1 did this, don't know the current behaviour).

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

Update:

更新:

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

You don't need this for runtime exceptions, this is the default behaviour of EJBs.

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