首页 > 其他分享 >【Spring事物三千问】TransactionSynchronizationManager的原理分析

【Spring事物三千问】TransactionSynchronizationManager的原理分析

时间:2023-02-05 16:00:38浏览次数:42  
标签:TransactionSynchronizationManager 事务 transaction Spring DB TransactionSynchroniz

TransactionSynchronizationManager

TransactionSynchronizationManager 是管理每个线程的DB连接资源和事务同步的核心委托类。

如果事务同步未处于活动状态,则表示当前没有事务,或者事务管理器不支持事务同步。

TransactionSynchronizationManager 中定义了很多 ThreadLocal 变量,来保存事务相关的信息

public abstract class TransactionSynchronizationManager {

    // 保存DB连接资源。
    // 使用 Object 来保存是因为每种平台的DB连接资源对象可能不一样,比如:JDBC,Hibernate,EJB 等使用的 DB 连接对象是不一样的。 
    private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");

    // 事务同步回调。每个线程可以注册多个事务同步回调
    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");
    
    // 当前事务的名称  
    private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<>("Current transaction name");
    // 当前事务是否只读  
    private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<>("Current transaction read-only status");
    // 当前事务的隔离级别  
    private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<>("Current transaction isolation level");
    // 事务是否开启  
    private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<>("Actual transaction active");
}

不同的平台的DB连接资源对象可能是不一样的,反映在 Spring 源码当中就是调用 TransactionSynchronizationManager#bindResource() 方法时,绑定的 DB 连接资源不同。

TransactionSynchronizationManager 事务同步管理器的核心逻辑

  • 为什么要使用事务同步管理器 TransactionSynchronizationManager?
    答:不同平台的事务管理实现方式不同,DB 连接资源对象也可能不同,所以,通过 TransactionSynchronizationManager 将事务资源相关的信息保存在各个 ThreadLocal 对象中,可以隔离不同平台带来的差异。

将当前 DB 连接资源绑定到当前线程中的代码如下:
doGetConnection.png

不管是什么平台,Spring 封装的获取 DB 连接资源的编程模型都是统一的:

  1. 从当前线程中获取绑定的 DB 连接资源 --- TransactionSynchronizationManager#getResource()
  2. 如果没有获取到,则从 DataSource 中获取 DB 连接资源
  3. 将获取到的 DB 连接资源绑定到当前线程中 --- TransactionSynchronizationManager#bindResource()

TransactionSynchronization 事务回调扩展

Spring 会通过 AbstractPlatformTransactionManager#processCommit() 去处理事务的提交,在事务提交前后预留了一些扩展点。

处理事务提交的代码如下:
processCommit.png

可以看到,事务提交前后有一些 triggerXxx 方法是 Spring 预留的扩展点。底层是调用当前线程中注册的事务同步回调 TransactionSynchronization 中的方法。

// TransactionSynchronizationUtils#triggerBeforeCommit()  
public static void triggerBeforeCommit(boolean readOnly) {
    for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {
        synchronization.beforeCommit(readOnly);
    }
}

事务回调的扩展方法有: triggerBeforeCommit()、triggerBeforeCompletion()、triggerAfterCommit()、triggerAfterCompletion()
参考: org.springframework.transaction.support.TransactionSynchronization

https://www.cnblogs.com/kkkfff/p/13778692.html
https://carlzone.blog.csdn.net/article/details/108659198

慎用事务回调扩展

问题一:triggerXx 方法中操作数据库的话,对原事物是否有影响?

TransactionSynchronization 扩展出的方法中,能不能在方法里面操作数据库,要打个问号??
这里面带来的问题是:如果在 triggerXx 方法中操作数据库,是新开启一个连接,还是在原来的事务连接中进行操作? 如果操作不当,容易引发问题,要慎用! https://www.jianshu.com/p/149de22ca54b

其实,这些预留扩展的 trigger 方法都可以通过其他变通的方式来书写,没必要一定要使用。在博主的工作中,还从未碰到过不使用 trigger 扩展解决不了的场景。

问题二:triggerAfterCommit()、triggerAfterCompletion()

在阅读源码的过程中,可以发现: 在 triggerAfterCommit()、triggerAfterCompletion() 中使用事物的话,不会对上层事物产生任何影响了,因为 spring-tx 对异常的处理没有包含 triggerAfterCommit()、triggerAfterCompletion(), 所以,上层事物不会再处理 triggerAfterCommit()、triggerAfterCompletion() 方法里面抛出的异常。

还有个问题是需要尤其注意的,triggerAfterCommit()、triggerAfterCompletion() 方法中使用事物的话,还有一个风险,内外事物如果使用的是同一个事物的话,那么,事物连接在这个时候可能已经被 连接池回收了,从而导致诡异的问题。

可以参看源码注释: org.springframework.transaction.support.TransactionSynchronization#afterCompletion
TransactionSynchronization#afterCommit 与 TransactionSynchronization#afterCompletion 是类似的。

Invoked after transaction commit/rollback. Can perform resource cleanup after transaction completion.
NOTE: The transaction will have been committed or rolled back already, but the transactional resources might still be active and accessible.
As a consequence, any data access code triggered at this point will still "participate" in the original transaction, 
allowing to perform some cleanup (with no commit following anymore!), unless it explicitly declares that it needs to run in a separate transaction. 
Hence: Use PROPAGATION_REQUIRES_NEW for any transactional operation that is called from here.

标签:TransactionSynchronizationManager,事务,transaction,Spring,DB,TransactionSynchroniz
From: https://blog.51cto.com/laowang6/6038301

相关文章

  • SpringBoot访问windows共享文件
    前言最近有项目需要开发档案打包下载功能,其中包含很多大附件,项目使用minio存储且不在同一台服务器上,为了优化速度决定使用windows共享功能进行文件传输SMB1.0集成jcifs类......
  • SpringBoot访问windows共享文件
    前言最近有项目需要开发档案打包下载功能,其中包含很多大附件,项目使用minio存储且不在同一台服务器上,为了优化速度决定使用windows共享功能进行文件传输SMB1.0集成jcifs......
  • Spring4 - IoC容器
    容器:IoCIoC是InversionofControl的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序......
  • Spring Cloud Eureka
    资料springCloud官网springCloud中文开发文档springCloud中文社区网站  基础项目构建maven父工程建立,公用模块建立,服务提供模块建立消费模块建立在SpringCloud中,......
  • spring框架面试
    ssm框架面试Spring面试问题:1.问题集合一Mybatis面试问题:1.......
  • Spring整合Mybatis
    首先导入依赖1<properties>2<!--版本锁定-->3<spring.version>5.0.2.RELEASE</spring.version>4<log4j.version>1.2.17</log4j.version>......
  • Spring3 - Log4j2日志框架
    启用Log4j2日志框架Log4j2日志概述在项目开发中,日志十分的重要,不管是记录运行情况还是定位线上问题,都离不开对日志的分析。日志记录了系统行为的时间、地点、状态等相关......
  • spring.jackson.default-property-inclusion 不生效问题分析
    背景项目里每个返回体里都有@JsonInclude(JsonInclude.Include.NON_NULL)这个注解,也就是不返回null字段想有没有办法全局配置一下,这样就不用每个类都加这个注解了sprin......
  • Spring2 - 入门案例
    Spring基本操作导入依赖在pom.xml中添加依赖添加依赖:<dependencies><!--springcontext依赖--><!--当你引入SpringContext依赖之后,表示将Spring的基础依......
  • Spring1 - 介绍
    Spring介绍最核心模块IoC:InverseofControl控制反转把创建对象的过程交给Spring进行管理AOP:AspectOrientedProgramming面向切面编程代码简化:把方法中......