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

时间:2013-04-02 15:20:34

标签: java spring hibernate transactions rollback

这是我的问题:

我在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: Transaction marked as rollbackOnly但它并没有真正帮助我。

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

更新

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

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

@Transactional注释可以放在界面之前   定义,接口上的方法,类定义或公共   一个班级的方法。

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

即使它正在运作,问题仍然存在,因为它有一种奇怪的行为,我想理解为什么它不应该像它应该那样。

1 个答案:

答案 0 :(得分:36)

默认情况下,Spring事务通过使用处理事务和异常的代理包装Spring bean来工作。当您从method2()致电method1()时,您已完全绕过此代理,因此无法启动新交易,并且您有效地呼叫method2()来自与method1()调用打开的交易相同的交易。

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

the documentation中描述了这一点。