19

这是我的问题:

我在 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
  • 尝试并赶上method2

但这并没有改变什么。

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

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

更新

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

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

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

  • 我也尝试使用Exception代替RuntimeException(因为它更合适)但它也没有改变任何东西。

即使它正在工作,问题仍然悬而未决,因为它有一种奇怪的行为,我想了解为什么它的行为不像它应该的那样。

4

1 回答 1

41

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

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

这在文档中有所描述。

于 2013-04-02T16:32:26.810 回答