一尘不染

@Transactional(propagation = Propagation.REQUIRES_NEW)的异常行为

spring

这是我的问题:

我正在Java EE / Spring / Hibernate应用程序上运行批处理。此批次称为method1。此方法调用method2可以抛出的UserExceptiona(一个扩展类RuntimeException)。看起来是这样的:

@Transactional
public class BatchService implements IBatchService {
 @Transactional(propagation=Propagation.REQUIRES_NEW)
 public User method2(User user) {
   // Processing, which can throw a RuntimeException
 }

 public void method1() {
   // ...
   try {
     this.method2(user);
   } catch (UserException e) {
     // ...
   }
   // ...
 }
}

随着执行的继续,会捕获到异常,但是在method1关闭事务时,将引发RollbackException。

这是堆栈跟踪:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy128.method1(Unknown Source)
at batch.BatchController.method1(BatchController.java:202)

method2不抛出此异常时,它将很好地工作。

我尝试过的

  • 设置@Transactional(noRollbackFor={UserException.class}))上method1
  • 尝试赶上 method2
    但这并没有改变任何东西。

由于异常发生在发生回滚的不同事务中,所以我不明白为什么它不起作用。我看了一下:Jpa事务javax.persistence.RollbackException:事务标记为rollbackOnly,但它并没有真正帮助我。

如果有人可以给我一个线索,我将非常感激。

我通过设置propagation=Propagation.REQUIRES_NEW调用方法method2(实际上是发送异常的方法)来使其工作。此方法在与my非常相似的类中定义BatchService。所以我不明白为什么它可以在这个级别而不是在这个级别上工作method2。

  • 我将其设置method2为public,因为@Transactional如果该方法是私有的,则不考虑注释,如文档中所述:

@Transactional批注可以放在接口定义,接口上的方法,类定义或类上的公共方法之前。

  • 我也尝试使用Exception代替RuntimeException(因为它更合适),但是它也没有改变任何东西。
    即使它工作正常,问题仍然悬而未决,因为它的行为很奇怪,我想理解为什么它的表现不如预期。

阅读 2507

收藏
2020-04-20

共1个答案

一尘不染

默认情况下,Spring事务通过使用代理处理Spring Bean来工作,该代理处理事务和异常。method2()从调用时method1(),你将完全绕过该代理,因此它无法启动新事务,并且实际上是method2()从与调用打开的事务相同的事务中进行调用method1()

相反,当你从中调用另一个注入的bean method1()的方法时,实际上是在事务代理上调用方法。因此,如果此外来方法用REQUIRES_NEW标记,则代理将启动新事务,并且你可以捕获异常method1()并恢复外部事务。

2020-04-20