这是我的问题:

我正在Java EE/Spring/Hibernate应用程序上运行批处理。该批处理称为method1。此方法调用method2,它可以引发UserException(扩展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
  • try catch method2

  • 但这并没有改变任何东西。

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

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

    更新

    我通过在propagation=Propagation.REQUIRES_NEW调用的方法上设置method2(实际上是发送异常的方法)来使其工作。此方法在与BatchService非常相似的类中定义。所以我不明白为什么它可以在这个级别上工作,而不是在method2上工作。
  • 我已将method2设置为public,因为如文档中所述,如果方法是私有(private)的,则不考虑注释@Transactional:


  • 我也尝试使用Exception而不是RuntimeException(因为它更合适),但是它也没有任何改变。

  • 即使工作正常,问题仍然悬而未决,因为它的行为很奇怪,我想理解为什么它的表现不如预期。

    最佳答案

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

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

    这在the documentation中进行了描述。

    07-24 09:37
    查看更多