EJB:避免事务回滚

24

当一个EJB的(事务性)方法调用另一个EJB的(事务性)方法,并且第二个方法中抛出异常,但在第一个方法中被捕获时,似乎当第二个方法返回时事务会自动回滚,即使第一个方法捕获了它,这是真的吗?如何避免这种情况?

场景如下:

@Stateless
class ClassA {
   @EJB
   ClassB objectB;

   methodA() { 
       try { 
            objectB.methodB(); 
       }
       catch(Exception e) {
            //Here the transaction started in this method is 
            //automatically rolled back. Is this avoidable?
       } 
   }
}

@Stateless
class ClassB {
   methodB() throws Exception { throw new Exception() }
}
2个回答

28

如果你抛出一个RuntimeException或任何带有@ApplicationException注解且具有rollback属性设置为true的异常,事务将被回滚,因此:

@ApplicationException(rollback=true)
public class MyException extends Exception {
    // ...
}

将回滚当前事务。

默认情况下,ApplicationException 不会回滚您的事务。

如果您不想让 methodB 回滚您的事务,您可以更改 ApplicationException 的回滚行为或防止事务共享。

后者可以通过更改 methodB 的 TransactionAttribute(例如,更改为 RequiresNew)来实现。然后 methodA 事务(Tx1)将被挂起,并且如果 methodB 抛出异常导致其事务(Tx2)回滚,则仍然可以在 methodA 中捕获它并防止 methodA 事务(Tx1)的回滚。


如果在后者中,您捕获了methodB异常,那么可以进行一些记录等操作,但是还需要再次抛出同样的异常,这样会正常回滚methodA吗? - W0lfw00ds

12

是的,这是真的,如果异常是运行时异常。已检查异常不会导致事务回滚。

为了避免这种情况,请确保在methodB中的代码不会抛出任何运行时异常。运行时异常通常表示存在错误或状态不允许继续工作。


抱歉,我的错。我修改了问题并注明它会抛出一个已检查的异常,在这种情况下事务是否也会回滚? - Mr.Eddart
1
不,如果异常是已检查的异常,则不应该回滚。 - JB Nizet
1
如果你只知道异常是被检查的,那么你不能确定它是否会回滚你的事务。如果它是@ApplicationException(rollback=true),它可能会回滚你的事务。 - Piotr Nowicki
5
@Piotr说得对。除非使用@ApplicationException(rollback=true)进行注释,否则受检异常不会回滚事务。除非使用@ApplicationException(rollback=false)进行注释,否则运行时异常将回滚事务。 - JB Nizet
2
@JBNizet +1,因为提出了rollback=false的RuntimeException案例。 - Piotr Nowicki
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接