栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring中事务源码解读

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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框架的事务支持模型的优势

传统上,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来使用

    
		
        
            
            
            
            
        
    

  
	

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

注解配置方式 在 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 的属性配置: 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中使用的也是编程式事务管理方式

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

 

Spring事务管理API  Spring 为事务管理提供了统一的抽象建模,这样我们使用 Spring 来进行事务管理时,就只需要学会这套 API即可,无论底下使用的是何种事务管理方式, jdbc 也好, jpa 也好, hibernate 也好, jta 也好。我们的业务代码中都是面向spring 的事务 API 。 TransactionDefinition TransactionDefinition :事务定义。 Spring 事务管理框架将为我们管理事务,但不清楚该如何替我们管 理,我们就通过事务定义来定义我们需要的事务管理信息,把这些信息给事务管理器,它就知道我们的意图了。 TransactionDefinition接口的内部

ISOLATION_DEFAULT :使用的是底层(数据库)默认的隔离级别,不同的数据库默认隔离级别不同, 数据库也是可以配置这个默认属性的。 TransactionDefinition 实现体系 默认的事务配置 , 包括下面的。

TransactionAttribute 前面的事务定义中没有回滚的信息,在 TransactionAttribute 有定义

TransactionDefinition的继承体系

PlatformTransactionManager PlatformTransactionManager 平台级的事务管理器,它抽象定义了事务管理行为,不同的事务管理实现实现该接口。我们编程面向该接口。 PlatformTransactionManager 的接口定义 接口中定义了的事务管理行为。

 PlatformTransactionManager的实现

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

 

开启新的事务方法

创建一个新的同步 开始事务 初始化事务同步控制的信息

 统一控制  dao层的方法  。

 prepareSynchronization

同步器加锁

 挂起当前的事务操作

 判断事务是否活跃。

 并 返回 事务的holder  放的是事务挂起信息

 

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

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

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

控制  事务等等,保存点。

 

 DefaultTransactionStatus

DataSourceTransactionManager DataSourceTransactionManager 是基于 jdbc connection 的本地事务管理实现。多个方法调用参与到同一个事务,是通过共用connection 来完成的,这里面实现的标准

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

断点调试看执行过程

使用的地方

AbstractPlatformTransactionManager.getTransaction  打断点看情况

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

 

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

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

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

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

 这部分做的就是 把事务连接 放到事务对象中。datasourcetrancationmanage中的处理

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

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

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

JdbcTemplate.execute UserDao 中是使用 JdbcTemplate 来进行的操作,找到 JdbcTemplate 的 update 操作的获取 connection 的代码,加断点,然后F8 ,让程序执行到这里,看下调用栈。

F8,JDBCTeamplate.execute的调用栈 

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

 TransactionSynchronizationManager#doGetResource代码,又回到了ThreadLocal的resources

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

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

事务传播行为

 

 声明式事务处理过程 标签解析 TxNamespaceHandler
@Override 
public void init() { 
    registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());     
     registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); 
     registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser()); 
}
TxAdviceBeanDefinitionParser 标签的解析器 TxAdviceBeanDefinitionParser    TxAdviceBeanDefinitionParser的关键方法

TransactionInterceptor TransactionInterceptor 就是一个环绕织入 MethodInterceptor 的实现

浏览TransactionInterceptor的代码,重点:invoke(MethodInvocation invocation)方法 invokeWithinTransaction方法

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

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

 

它的重点方法是 invokeWithinTransaction TransactionAttributeSource

浏览TransactionAttributeSource接口定义

浏览TransactionAttributeSource 的继承体系  

 

 切面增强过程

TransactionAspectSupport.invokeWithinTransaction 方法 从代码中可看出:标准的编程式事务管理流程

获得TransactionAttributeSource获得事务定义TransactionAttribute获得TransactionManager

如果有对应的事务定义并且事务管理器是ReactiveTransactionManager类型的,进行响应的 处理如果没有对应的事务定义,或者事务管理器不是

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

事务监听

Data Access (spring.io)

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

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

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

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

 触发事件监听的一个注解

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

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

Spring 中的事件发布订阅机制 整体而言 Spring 的事件机制是通过发布订阅来达到的。

 

它需要注册一个事件监听处理器, EventListenerMethodProcessor 就是用来处理事件方法监听,只不过最终使用 TransactionalEventListenerFactory 生成一个 Adapter 适配器。

 

 注解的扫描起来,进行存储起来。

ApplicationListenerMethodAdapter 下面有一个 ApplicationListenerMethodTransactionalAdapter 类,用来处理事务监听器的。 AbstractPlatformTransactionManager#triggerAfterCommit TransactionSynchronizationUtils#invokeAfterCompletion AbstractPlatformTransactionManager#triggerBeforeCommit TransactionSynchronizationUtils#triggerBeforeCommit after 事件触发

 事件发布的堆栈

自定义注解  @import注解

 通过@import导入一个或多个@link Configuration类   

4.2后,三种情况:@Configuration、importSelector、importBeanDefinitionRegistrar 的实现会被IOC注册

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

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

 

 AnnotationConfigBeanDefinitionParser 跟着进去

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

ConfigurationClassPostProcessor#processConfigBeanDefinitions

 ConfigurationClassParser.processimports(…)方法

 

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

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

分布式事务JTA 

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

 

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

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

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

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

 

XA 规范 什么是 XA 规范

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

 

 

XA- 两阶段提交 第一阶段:准备阶段

第二阶段:提交/回滚

 JTA JTA: Java Transaction API JAVA 根据 XA 规范提出的事务处理 API 标准 目的:统一 API, 简化程序员的学习,简化编程

 javax下的jar包


    javax.transaction
    javax.transaction-api
    1.3

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 来处理事务
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/715650.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号