Spring中事务源码解读

前言

之前的文章是解析spring中ioc源码 以及 aop源码 ,包括核心的bean的生命周期 以及 各个扩展部分,以及 aop源码 如何开启注解时, 解析注解标签时,将 所有 aop所拥有的控件在bean实例化 之前 和实例化之后的一个 扩展 AnnotationAwareAspectJAutoProxyCreator 这个类上 面做的所有的处理和扩展。本篇文章会继续 研究 事务源码部分, 包括事务隔离级别,以及 事务如何实现的。

Spring事务管理

​​​​​​Data Access (spring.io)

Spring 框架为事务管理提供一个一套统一的抽象,带来的好处有:
1. 跨不同事务 API 的统一的编程模型,无论你使用的是 jdbc jta jpa hibernate
2. 支持声明式事务
3. 简单的事务管理 API
4. 能与 spring 的数据访问抽象层完美集成

Spring中事务源码解读_第1张图片

 Spring框架的事务支持模型的优势

传统上,Java EE 开发人员对事务管理有两种选择:全局事务或本地事务,这两者都有很大的局限性。接下来的两节将回顾全局和本地事务管理,然后讨论Spring框架的事务管理支持如何解决全局和本地事务模型的局限性。

事务概念

Isolation 隔离级别
此事务与其他事务的工作隔离的程度。例如,该事务能否看到来自其他事务的未提交的写操作
  • READ_UNCOMMITTED 读未提交
  • READ_COMMITTED 读已提交
  • REPEATABLE_READ 可重复读
  • SERIALIZABLE 序列化(串行)
Read/Write 读写
该事务操作是读、是写、还是有读有写
Timeout 超时
对事务执行的时长设置一个阀值,如果超过阀值还未完成则回滚。
Propagation 传播行为
当一个方法开启事务后,在方法中调用了其他的方法,其他方法可能也需要事务管理,此时就涉及事务该如何传播了。
1. TransactionDefinition.PROPAGATION_REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
2. TransactionDefinition.PROPAGATION_REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。
3. TransactionDefinition.PROPAGATION_SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
4. TransactionDefinition.PROPAGATION_NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。
5. TransactionDefinition.PROPAGATION_NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。
6. TransactionDefinition.PROPAGATION_MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
7. TransactionDefinition.PROPAGATION_NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED。
SavePoint 保存点
事务中可以设置一些保存点(阶段标识),回滚时可以指定回滚到前面的哪个保存点。
Commit/Rollback 提交 / 回滚
提交、回滚事务

Spring中的事务使用

 
	 
		org.springframework 
		spring-jdbc 
		5.2.8.RELEASE
	 
	 
		com.alibaba 
		druid 
		1.2.1 
	 
	 
		mysql 
		mysql-connector-java 
		8.0.19 
	 
	 
	 
		javax.transaction 
		javax.transaction-api 
		1.3 
	 
	 
	 
		com.atomikos 
		transactions-jdbc 
		4.0.6 
	 
	 
	 
		com.atomikos 
		transactions-jms 
		4.0.6 
		
	

XML配置方式

application.xml 文件中配置
 
 
    
 
Spring 事务管理起到的作用
  • 不配置事务运行Main类,查看数据库操作结果
  • 配置事务运行Main类,查看数据库操作结果
UserService 操作了 User Log 两张表,两张表,在配置和不配置事务管理的情况下,两张数据库表一致性不一样。
其次需要结合 aop来使用

    
		
        
            
            
            
            
        
    

  
	

以及隔离级别处理两个事务之间的关系,回滚 与不回滚的操作

Spring中事务源码解读_第2张图片

注解配置方式

xml 中开始注解方式支持
 
或以注解的方式开启
@Configuration 
@ComponentScan("com.study.mike.spring.sample.tx") 
@ImportResource("classpath:com/study/mike/spring/sample/tx/application.xml") 
@EnableTransactionManagement 
public class TxMain { 
}
在要加事务管理的类或方法上加 @Transactional 注解
@Transactional(propagation = Propagation.REQUIRES_NEW) 
public void insertLog(Log log) { 
    this.logDao.insert(log);
}
掌握 @Transactional 的属性配置:
Spring中事务源码解读_第3张图片
rollbackFor 默认情况下是对 RuntimeException 进行回滚。

声明式事务管理

 Spring提供基于AOP的声明式事务管理,当有大量的事务需要进行管理时,声明式事务管理更合适,让 我们的事务管理变得简单、易用!

编程式事务管理

需要快速简单的事务管理时,适用编程式事务管理。

// 1、创建事务定义
		DefaultTransactionDefinition definition = new DefaultTransactionDefinition();

		// 2、根据定义开启事务
		TransactionStatus status = txManager.getTransaction(definition);

		try {
			this.userDao.insert(u);
			Log log = new Log(System.currentTimeMillis() + "", System.currentTimeMillis() + "-" + u.getUserName());
			// this.doAddUser(u);
			this.logService.insertLog(log);
			// 3、提交事务
			txManager.commit(status);
		} catch (Exception e) {
			// 4、异常了,回滚事务
			txManager.rollback(status);
			throw e;
		}
		// 在TransactionTemplate中使用的也是编程式事务管理方式

Spring中事务源码解读_第4张图片

TransactionDefinition 结构
编程式事务管理简化使用 TransactionTemplate TransactionTemplate 中的 execute 方法代码实现:

 Spring中事务源码解读_第5张图片

Spring事务管理API 

Spring 为事务管理提供了统一的抽象建模,这样我们使用 Spring 来进行事务管理时,就只需要学会这套 API即可,无论底下使用的是何种事务管理方式, jdbc 也好, jpa 也好, hibernate 也好, jta 也好。我们的业务代码中都是面向spring 的事务 API

TransactionDefinition

TransactionDefinition :事务定义。 Spring 事务管理框架将为我们管理事务,但不清楚该如何替我们管 理,我们就通过事务定义来定义我们需要的事务管理信息,把这些信息给事务管理器,它就知道我们的意图了。

TransactionDefinition接口的内部

Spring中事务源码解读_第6张图片

ISOLATION_DEFAULT :使用的是底层(数据库)默认的隔离级别,不同的数据库默认隔离级别不同, 数据库也是可以配置这个默认属性的。
TransactionDefinition 实现体系
Spring中事务源码解读_第7张图片
默认的事务配置 , 包括下面的。
Spring中事务源码解读_第8张图片

Spring中事务源码解读_第9张图片

TransactionAttribute
前面的事务定义中没有回滚的信息,在 TransactionAttribute 有定义
Spring中事务源码解读_第10张图片

TransactionDefinition的继承体系

Spring中事务源码解读_第11张图片

Spring中事务源码解读_第12张图片

PlatformTransactionManager

PlatformTransactionManager 平台级的事务管理器,它抽象定义了事务管理行为,不同的事务管理实现实现该接口。我们编程面向该接口。
PlatformTransactionManager 的接口定义
接口中定义了的事务管理行为。
Spring中事务源码解读_第13张图片

 PlatformTransactionManager的实现

Spring中事务源码解读_第14张图片

分布式事务,则用 JTA
AbstractPlatformTransactionManager
PlatformTransactionManager 的三个方法的实现逻辑
// 下面的三个动作都是由这个类来完成的
 getTransaction() 
commit() 
rollback()
getTransaction的流程 
1. 获取事务对象
2. 如果当前存在事务,则根据事务定义中的传播行为来进行处理
3. 当前不存在事务,则根据事务定义的传播行为来决定如何处理
3.1 如果一定需要事务,而当前又不存在事务,则抛出异常
3.2 如果是下面的三种传播行为,则创建事务
挂起当前事务
开始一个新的事务
3.3 如果传播行为是默认的,使用一个空的事务,交给底层去进行处理
Spring中事务源码解读_第15张图片

 Spring中事务源码解读_第16张图片

开启新的事务方法

创建一个新的同步
开始事务
初始化事务同步控制的信息
Spring中事务源码解读_第17张图片

Spring中事务源码解读_第18张图片

Spring中事务源码解读_第19张图片

 统一控制  dao层的方法  。Spring中事务源码解读_第20张图片

 prepareSynchronization

同步器加锁

Spring中事务源码解读_第21张图片

Spring中事务源码解读_第22张图片

 挂起当前的事务操作

Spring中事务源码解读_第23张图片

 判断事务是否活跃。

 并 返回 事务的holder  放的是事务挂起信息Spring中事务源码解读_第24张图片

 Spring中事务源码解读_第25张图片

 对于 事务活跃的情况,把相关属性装起来,作一个切换。

Spring中事务源码解读_第26张图片

 这些挂起的资源 都放到新的状态里面去了

Spring中事务源码解读_第27张图片

TransactionStatus

TransactionStatus 事务状态,持有事务的状态信息。事务管理代码可通过它获取事务状态、以及显式地设置回滚(代替异常的方式)。它继承了SavePoint 接口。在它的实现中会持有事务的很多对象:如事务对象、被挂起的事务资源等等。
TransactionManager 中获取事务得到它,提交 / 回滚事务时要给入它:
Spring中事务源码解读_第28张图片

控制  事务等等,保存点。

 Spring中事务源码解读_第29张图片

 DefaultTransactionStatus

Spring中事务源码解读_第30张图片

DataSourceTransactionManager

DataSourceTransactionManager 是基于 jdbc connection 的本地事务管理实现。多个方法调用参与到同一个事务,是通过共用connection 来完成的,这里面实现的标准
Spring中事务源码解读_第31张图片

 获取事务,获得连接  处理事务。

断点调试看执行过程

使用的地方

Spring中事务源码解读_第32张图片

AbstractPlatformTransactionManager.getTransaction  打断点看情况

Spring中事务源码解读_第33张图片

getTransaction ,看调用栈
获取到连接,并做绑定起来。

 Spring中事务源码解读_第34张图片

数据源  datasource获取到连接内容 。

Spring中事务源码解读_第35张图片

Spring中事务源码解读_第36张图片

拿到事务   这里面就是 为后面的做的处理。

Spring中事务源码解读_第37张图片

 两个service 调用了dao,放到数据库连接上。

最后 走到 开启事务的部分。

Spring中事务源码解读_第38张图片

 这部分做的就是 把事务连接 放到事务对象中。datasourcetrancationmanage中的处理Spring中事务源码解读_第39张图片

 设置 自动连接的东西   以及创建事务前的处理

Spring中事务源码解读_第40张图片

 这里创建好的事务将他绑定到 对应的threadlocal上面去。

Spring中事务源码解读_第41张图片

 其实最终你会发现  在 事务框架中 通过threadlocal将对应的 datasource  和 连接 存到这里面做一个缓存起来。  并且  创建新事务时将 这个存到事务对象中,当然也会包括许多 前置化的处理以及属性的设置。

JdbcTemplate.execute
UserDao 中是使用 JdbcTemplate 来进行的操作,找到 JdbcTemplate update 操作的获取 connection 的代码,加断点,然后F8 ,让程序执行到这里,看下调用栈。
Spring中事务源码解读_第42张图片

F8JDBCTeamplate.execute的调用栈 

Spring中事务源码解读_第43张图片

F5进入DataSourceUtils.getConnection(obtainDataSource()),看它如何获取Connection  

Spring中事务源码解读_第44张图片

 TransactionSynchronizationManager#doGetResource代码,又回到了ThreadLocalresources

ThreadLocal 获得相同的数据库连接,才能进行事务的管理和控制。
第二次进到 getTransaction
Spring中事务源码解读_第45张图片
UserService LogService 都用了同一个 Connection ,也处于同一个事务中。
跟代码看已存在事务的处理逻辑, AbstractPlatformTransactionManager#handleExistingTransaction方法的实现。

Spring中事务源码解读_第46张图片

 验证其他两种传播行为,及其他的组合情况

事务传播行为

Spring中事务源码解读_第47张图片

 Spring中事务源码解读_第48张图片

 声明式事务处理过程

标签解析
TxNamespaceHandler
@Override 
public void init() { 
    registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());     
     registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); 
     registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser()); 
}
Spring中事务源码解读_第49张图片
TxAdviceBeanDefinitionParser
标签的解析器 TxAdviceBeanDefinitionParser    TxAdviceBeanDefinitionParser的关键方法

Spring中事务源码解读_第50张图片

TransactionInterceptor
TransactionInterceptor 就是一个环绕织入 MethodInterceptor 的实现
  • 浏览TransactionInterceptor的代码,重点:invoke(MethodInvocation invocation)方法 invokeWithinTransaction方法

Spring中事务源码解读_第51张图片

  •  浏览TransactionInterceptor的继承体系,事务处理的逻辑都在TransactionAspectSupport

Spring中事务源码解读_第52张图片

  • 浏览TransactionAspectSupport,它里面有如下属性

 

它的重点方法是 invokeWithinTransaction
TransactionAttributeSource
  • 浏览TransactionAttributeSource接口定义

Spring中事务源码解读_第53张图片

  • 浏览TransactionAttributeSource 的继承体系  

Spring中事务源码解读_第54张图片

 Spring中事务源码解读_第55张图片

 切面增强过程

TransactionAspectSupport.invokeWithinTransaction 方法
从代码中可看出:标准的编程式事务管理流程
  • 获得TransactionAttributeSource
  • 获得事务定义TransactionAttribute
  • 获得TransactionManager
  • 如果有对应的事务定义并且事务管理器是ReactiveTransactionManager类型的,进行响应的 处理
  • 如果没有对应的事务定义,或者事务管理器不是

Spring中事务源码解读_第56张图片

对于编程式事务的一个封装。

事务监听

Data Access (spring.io)

从 Spring 4.2 开始,事件的监听器可以绑定到事务的一个阶段。典型的例子是在事务成功完成时处理事件。当当前事务的结果实际上对侦听器很重要时,这样做可以更灵活地使用事件。

您可以使用 @EventListener 注释注册常规事件侦听器。如果需要将其绑定到事务,请使用@TransactionalEventListener。当您这样做时,默认情况下侦听器绑定到事务的提交阶段。 下一个示例显示了这个概念。假设一个组件发布了一个订单创建的事件,并且我们想要定义一个侦听器,该侦听器仅在发布它的事务成功提交后才处理该事件。以下示例设置了这样一个事件侦听器:

本质上就是一个EventListener,类似继承
@TransactionalEventListener
@Component
public class MyComponent {

    @TransactionalEventListener
    public void handleOrderCreatedEvent(CreationEvent creationEvent) {
        // ...
    }
}

Spring中事务源码解读_第57张图片

 触发事件监听的一个注解

Spring中事务源码解读_第58张图片

 @TransactionalEventListener 注释公开了一个阶段属性,该属性允许您自定义侦听器应绑定到的事务的阶段。有效阶段是 BEFORE_COMMIT、AFTER_COMMIT(默认)、AFTER_ROLLBACK 和 AFTER_COMPLETION,

它们聚合事务完成(无论是提交还是回滚)。 如果没有事务正在运行,则根本不会调用侦听器,因为我们无法遵守所需的语义。但是,您可以通过将注解的 fallbackExecution 属性设置为 true 来覆盖该行为。

Spring 中的事件发布订阅机制
整体而言 Spring 的事件机制是通过发布订阅来达到的。
Spring中事务源码解读_第59张图片

 

它需要注册一个事件监听处理器, EventListenerMethodProcessor
就是用来处理事件方法监听,只不过最终使用 TransactionalEventListenerFactory 生成一个 Adapter 适配器。
Spring中事务源码解读_第60张图片

Spring中事务源码解读_第61张图片 

 注解的扫描起来,进行存储起来。Spring中事务源码解读_第62张图片

ApplicationListenerMethodAdapter 下面有一个 ApplicationListenerMethodTransactionalAdapter
类,用来处理事务监听器的。
Spring中事务源码解读_第63张图片
AbstractPlatformTransactionManager#triggerAfterCommit
TransactionSynchronizationUtils#invokeAfterCompletion
AbstractPlatformTransactionManager#triggerBeforeCommit
TransactionSynchronizationUtils#triggerBeforeCommit
after 事件触发

Spring中事务源码解读_第64张图片

 事件发布的堆栈 Spring中事务源码解读_第65张图片

自定义注解

 @Import注解

 通过@Import导入一个或多个@link Configuration  

4.2后,三种情况:@Configuration、ImportSelector、ImportBeanDefinitionRegistrar
的实现会被IOC注册
Spring中事务源码解读_第66张图片

引入的类都可以作为 component 注册到ioc中

在spring中对于 import 的  解析  是在  ContextNamespaceHandler 中

Spring中事务源码解读_第67张图片

 

 AnnotationConfigBeanDefinitionParser 跟着进去

Spring中事务源码解读_第68张图片

 对于 import 注解来说 ConfigurationClassPostProcessor   是在这里做的处理的 

Spring中事务源码解读_第69张图片

ConfigurationClassPostProcessor#processConfigBeanDefinitions

Spring中事务源码解读_第70张图片

Spring中事务源码解读_第71张图片

 ConfigurationClassParser.processImports(…)方法

Spring中事务源码解读_第72张图片

 Spring中事务源码解读_第73张图片

最后放到configclass 以及 importstack 中进行 导入进去。

注解用来做配置,简化xml的配置信息。

分布式事务JTA 

 分布式事务  具有多个数据源

 Spring中事务源码解读_第74张图片

一个事务包含多个操作,多个操作操作了多个数据源,这样的事务称为分布式事务。
与普通事务的区别
普通事务操作,一个单一数据源事务
Spring中事务源码解读_第75张图片
单一数据源,事务管理可以借助数据源本地事务完成,实现简单!
分布式事务管理之困难:不可简单借助数据源本地事务完成!
一个分布式事务示例
Spring中事务源码解读_第76张图片

 尝试借助本地事务来完成事务管理

分布式事务管理需要什么
分布式事务管理需要的机制
1. 协调各数据源提交、回滚,及应对通信异常的管理机制。
2. 数据源需要支持这种机制。
3. 应对应用故障恢复的机制。

 从上面得出,做分布式事务管理需要的参与者

Spring中事务源码解读_第77张图片

 

XA 规范
什么是 XA 规范

 XA规范是X/Open(The open group)提出的分布式事务处理规范,分布式事务处理的工业标准。

Spring中事务源码解读_第78张图片

 Spring中事务源码解读_第79张图片

 

XA- 两阶段提交
第一阶段:准备阶段
Spring中事务源码解读_第80张图片

第二阶段:提交/回滚

Spring中事务源码解读_第81张图片

 JTA

JTA: Java Transaction API
JAVA 根据 XA 规范提出的事务处理 API 标准
目的:统一 API, 简化程序员的学习,简化编程
Spring中事务源码解读_第82张图片

 javax下的jar


    javax.transaction
    javax.transaction-api
    1.3

Spring中事务源码解读_第83张图片

JTA-API 构成
面向 TM RM 提供商的 API
 TransactionManager
 Transaction
 XARsource
 Xid
TM 实现提供商
JavaEE 应用服务器内建 JTA 事务管理( TM ),提供商:
  • Weblogic
  • Websphere

 开源、独立的JTA事务管理器(TM)组件:

  • Java Open Transaction Manager (JOTM)
  • JBoss TS
  • Bitronix Transaction Manager (BTM)
  • Atomikos
  • Narayana
RM 实现提供商
一般数据库厂商会提供实现
在连接池组件中一般也会提供包装实现:

Spring中应用JTA

Spring 中的 JTA
  • Spring自身并不提供jta TM实现,但提供了很好的集成
  • 根据TM的提供者不同,分为两种应用方式:
方式一:使用 javaEE 服务器内建的 TM
方式二:在没有实现 TM 的应用服务器上( Tomcat,jetty ),将独立 TM 组件集成到我们的 spring
用中
使用 JavaEE 服务器内建 TM
用法:做如下配置即可
xml 配置
或者 Java 配置
@Bean
public PlatformTransactionManager platformTransactionManager(){
    return new JtaTransactionManager();
}
说明: JtaTransactionManager 通过 JNDI 找到服务器提供的 java:comp/UserTransaction,
java:comp/TransactionManager 应用使用的数据源需是支持 xa 的数据源。
使用轻量级服务器 + 集成 TM 组件
操作步骤:
1. 引入 TM 组件的 jar (以 Atomikos 为例)
Spring 应用方式


    javax.transaction
    javax.transaction-api
    1.3



    com.atomikos
    transactions-jdbc
    4.0.6



    com.atomikos
    transactions-jms
    4.0.6
Spring Boot Starter 方式

    org.springframework.boot
    spring-boot-starter-jta-atomikos
    2.1.1.RELEASE
配置数据源,一定要是 XA 数据源
准备两个数据源
properties 配置数据源
# jdbc properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=root

db1.jdbc.url=jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
db2.jdbc.url=jdbc:mysql://127.0.0.1:3306/logdb?
useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC

Spring XML配置XA DataSource








    

   
    
        ${db1.jdbc.url}
        ${jdbc.username}
        ${jdbc.password}
    
   



……
配置事务管理器 TM
1. TransactionManager 的实现 bean
2. UserTransaction 的实现 bean
3. spring JtaTransactionManager (注入 TM UserTransaction
如果是在 spring-boot 中, 用 spring-boot-starter-jta-atomikos ,这步会自动配置好,不需手动配
置!
Spring 应用 JTA
使用 jta 需满足:
1. 数据源支持分布式事务
2. 要有 jta 的实现提供者( javaEE 服务器内建的或独立实现组件)
3. Spring 中配置使用 JtaTransactionManager 来处理事务

你可能感兴趣的:(spring,spring,java,后端)