@Transactional的奇怪行为(传播=Propagation.REQUIRES_NEW)

2022-09-02 12:00:28

这是我的问题:

我正在Java EE / Spring / Hibernate应用程序上运行批处理。此批处理调用 .此方法调用 一个 可以抛出的 (一个扩展的类)。这是它的样子:method1method2UserExceptionRuntimeException

@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) {
     // ...
   }
   // ...
 }
}

在执行继续时会捕获异常,但在事务关闭结束时,将引发 RollbackException。method1

下面是堆栈跟踪:

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的事务,但它并没有真正帮助我。

如果有人能给我一个线索,我会非常伟大。

更新

我通过设置调用 by 的方法(实际上是发送异常的方法)使它工作。此方法是在与 my 非常相似的类中定义的。所以我不明白为什么它在这个层面上工作,而不是在.propagation=Propagation.REQUIRES_NEWmethod2BatchServicemethod2

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

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

  • 我也试图使用而不是(因为它更合适),但它也没有改变任何东西。ExceptionRuntimeException

即使它正在工作,这个问题仍然悬而未决,因为它有一个奇怪的行为,我想知道为什么它没有像它应该的那样行事。


答案 1

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

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

这在文档中进行了描述。


答案 2

推荐