当 Spring Propagation.REQUIRES_NEW 嵌套在 Propagation.NESTED 中时的行为

Posted

技术标签:

【中文标题】当 Spring Propagation.REQUIRES_NEW 嵌套在 Propagation.NESTED 中时的行为【英文标题】:Behavior when Spring Propagation.REQUIRES_NEW is nested in a Propagation.NESTED 【发布时间】:2016-10-26 19:08:56 【问题描述】:

我有这样的代码

@Transactional(propagation = Propagation.NESTED)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class C1 
...
   public void xxx() 
      try 
         obj.someMethod();
       catch (Exception e) 
         C2.yyy();
      
   


public class C2 
    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false)
    public void yyy() 
        ...
    

我的假设是当obj.someMethod(); 抛出一个违反约束的异常时C2.yyy() 应该仍然能够将内容保存到数据库中。

但是我看到的是,当 C2.yyy() 被称为 Postgres 报告时

错误:当前事务被中止,命令被忽略,直到事务块结束

为什么要这样做?毕竟C2.yyy() 应该在不同的事务中运行,该事务应该不受调用代码中发生的状态的影响。不?

更新

在进一步调试时,我发现 - 让我们说调用堆栈是这样的

@Transactional(readOnly = false, propagation = Propagation.NESTED)
b1.m1()
       @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
       b2.m2()
              b3.m3()
                      b4.m4()

我的假设是由于 b2.m2() 上的注释,m4() 中的数据库代码将在新事务中执行。但似乎TransactionAspectSupport.java 中的代码仅在当前方法上查看事务注释,而不在堆栈上查看。当它在 m4() 上没有找到任何 @transactional 时,它假定 REQUIRES。这不正确吗?

【问题讨论】:

【参考方案1】:

正如DatabaseError: current transaction is aborted, commands ignored until end of transaction block 在这里回答的那样:“当查询产生错误并且您尝试运行另一个查询而不首先回滚事务时,这就是 postgres 所做的”。

意味着您的“obj”应该在自己的事务中运行并在异常时回滚。

关于更新中的问题:REQUIRES_NEW 总是创建一个新事务,它既是documented,也是经过测试的。

【讨论】:

但是“其他查询”应该在它自己的(新)事务中运行,因此应该不受先前运行的事务状态的影响。 REQUIRES_NEW 不是对此的保证吗? 好问题。我的理解是 REQUIRES_NEW 使用新连接,所以你是对的,理论上你的代码应该可以工作......我建议为'org.springframework.transaction'启用日志记录并重新运行你的示例。或者只是在 AbstractPlatformTransactionManager.getTransaction(...) 中放置一个断点 你使用普通的 JDBC、Hibernate 还是其他什么? 还有一个问题:您确定错误消息是由于 c2.yyy() 调用引起的吗?您不会重新抛出异常,因此调用 c2.yyy() 之后的代码将尝试使用断开的连接。 无休眠。纯 JDBC。我确实重新抛出了异常,但错误发生在此之前 - 即,一旦您尝试在 yyy() 中执行第一个 DB 操作,即使它是一个选择。我还注意到 Postgres tx_id 保持不变(来自 postgres 日志)。 This post 澄清 Postgres 不支持嵌套事务。如果没有嵌套的 tx 支持,我什至不知道这将如何工作。也许基于保存点!

以上是关于当 Spring Propagation.REQUIRES_NEW 嵌套在 Propagation.NESTED 中时的行为的主要内容,如果未能解决你的问题,请参考以下文章

当 spring-cloud-starter-zipkin 使用 zipkin.brave 时,为啥需要 Spring sleuth?

当需要 nativeJdbcExtractor 时,Spring 5 JDBC 方法是啥?

当所有其他消息完成处理时,Spring集成处理消息

401 Unauthorized - 当尝试点击 Spring 应用程序的休息服务时

Spring源码最难问题:当Spring AOP遇上循环依赖

当单个控制器收到许多请求时,Spring 如何处理线程安全?