当前位置: 首页 > 面试题库 >

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

令狐宏浚
2023-03-14
问题内容

这是我的问题:

我正在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(因为它更合适),但是它也没有改变任何东西。
    即使它工作正常,问题仍然悬而未决,因为它的行为很奇怪,我想理解为什么它的表现不如预期。

问题答案:

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

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



 类似资料:
  • 问题内容: 如果有人可以解释此注释的作用以及确切的使用时间: 谢谢 问题答案: 当传播设置为PROPAGATION_REQUIRED时,将为应用该设置的每种方法创建一个逻辑事务作用域。每个此类逻辑事务作用域可以单独确定仅回滚状态,而外部事务作用域在逻辑上与内部事务作用域无关。当然,在标准PROPAGATION_REQUIRED行为的情况下,所有这些范围都将映射到同一物理事务。因此,内部事务范围中设

  • 问题内容: 有人可以通过实际示例解释注释中的隔离和传播参数吗? 基本上,何时和为什么我应该选择更改其默认值。 问题答案: 好的问题,尽管不是一个简单的答案。 Propagation 定义事务之间的关系。常用选项: :代码将始终在事务中运行。创建一个新事务或重用一个事务(如果有)。 :代码将始终在新事务中运行。如果存在当前事务,则将其挂起。 Isolation 定义事务之间的数据契约。 :允许脏读。

  • 我想问一下这种行为的原因,因为在运行Spring方法/类时,我似乎不完全理解Hibernate中的和之间的区别。 下面的代码应该回滚DB操作,但它没有回滚(整个类注释为): 以下代码在引发异常时按预期回滚: save()方法来自类,因此它的代码是: 该实体是一个已存在的实体,因此我理解它正在执行。根据JPA规范: find方法(前提是在没有锁的情况下调用它或使用LockModeType.None调

  • 有两个代码片段。 在第一个例子中,我们从总是引发一些异常的任务中创建CompletableFuture。然后我们将“例外”方法应用于该未来,然后是“接受”方法。我们不会将Accept方法返回的新future分配给任何变量。然后我们对原始未来调用“join”。我们看到的是,“异常”方法以及“thenAccept”都已被调用。我们看到它是因为他们在输出中打印了适当的行。但“异常”方法并没有抑制该异常。