Spring中事务源码解读
2022/1/23 20:05:58
本文主要是介绍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 序列化(串行)
Spring中的事务使用
<!--transication--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.19</version> </dependency> <!-- jta api --> <dependency> <groupId>javax.transaction</groupId> <artifactId>javax.transaction-api</artifactId> <version>1.3</version> </dependency> <!-- atomikos 数据库的TM组件 --> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jdbc</artifactId> <version>4.0.6</version> </dependency> <!-- atomikos JMS 有MQ需要事务管理时加入 --> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jms</artifactId> <version>4.0.6</version> </dependency>
XML配置方式
application.xml 文件中配置<!-- 配置事务管理器 --> <bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>Spring 事务管理起到的作用
- 不配置事务运行Main类,查看数据库操作结果
- 配置事务运行Main类,查看数据库操作结果
<!-- 配置事务增强的advice --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!--配置事务的属性,通过method来进行配置--> <tx:attributes> <!-- all methods starting wit`h 'get' are read-only --> <tx:method name="get*" read-only="true" /> <!-- other methods use the default transaction settings (see below) --> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- 配置事务的AOP切面 --> <!--<aop:config> <aop:pointcut id="allService" expression="execution(* edu.courseware.spring.tx.service.*Service.*(..)))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="allService"/> </aop:config> -->
以及隔离级别处理两个事务之间的关系,回滚 与不回滚的操作
注解配置方式
在 xml 中开始注解方式支持<!-- 开启注解方式的事务配置支持( 注解的方式:@EnableTransactionManagement) --> <tx:annotation-driven transaction-manager="txManager"/>或以注解的方式开启
@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 <tx:advice> 标签的解析器 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<Order> 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包
<dependency> <groupId>javax.transaction</groupId> <artifactId>javax.transaction-api</artifactId> <version>1.3</version> </dependency>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
Spring中应用JTA
Spring 中的 JTA- Spring自身并不提供jta TM实现,但提供了很好的集成
- 根据TM的提供者不同,分为两种应用方式:
<tx:jta-transaction-manager />或者 Java 配置
@Bean public PlatformTransactionManager platformTransactionManager(){ return new JtaTransactionManager(); }说明: JtaTransactionManager 通过 JNDI 找到服务器提供的 java:comp/UserTransaction, java:comp/TransactionManager 应用使用的数据源需是支持 xa 的数据源。 使用轻量级服务器 + 集成 TM 组件 操作步骤: 1. 引入 TM 组件的 jar (以 Atomikos 为例) Spring 应用方式
<!-- jta api --> <dependency> <groupId>javax.transaction</groupId> <artifactId>javax.transaction-api</artifactId> <version>1.3</version> </dependency> <!-- atomikos 数据库的TM组件 --> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jdbc</artifactId> <version>4.0.6</version> </dependency> <!-- atomikos JMS 有MQ需要事务管理时加入 --> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jms</artifactId> <version>4.0.6</version> </dependency>Spring Boot Starter 方式
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> <version>2.1.1.RELEASE</version> </dependency>配置数据源,一定要是 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
<!-- 加载配置参数 --> <context:property-placeholder location="classpath:com/study/mike/spring/sample/jta/application.properties"/> <!-- xa数据源1 --> <bean id="db1DataSource“ class="com.atomikos.jdbc.AtomikosDataSourceBean "init-method="init" destroy-method="close"> <!-- 给数据源取个唯一区分的名称 --> <property name="uniqueResourceName" value="mysql/db01" /> <!-- 真正使用的 XA DataSource 类名 --> <property name="xaDataSourceClassName"value="com.alibaba.druid.pool.xa.DruidXADataSource" /> <!-- 数据源连接相关配置参数 --> <property name="xaProperties"> <props> <prop key="url">${db1.jdbc.url}</prop> <prop key="username">${jdbc.username}</prop> <prop key="password">${jdbc.password}</prop> </props> </property> </bean> <!-- xa数据源2 --> <bean id="db2DataSource“ class="com.atomikos.jdbc.AtomikosDataSourceBean“ init-method="init" destroy-method="close"> …… </bean>配置事务管理器 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中事务源码解读的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南