【Spring源码分析】透过源码看透Spring事务

阅读此需阅读下面这些博客先
【Spring源码分析】Bean的元数据和一些Spring的工具
【Spring源码分析】BeanFactory系列接口解读
【Spring源码分析】执行流程之非懒加载单例Bean的实例化逻辑
【Spring源码分析】从源码角度去熟悉依赖注入(一)
【Spring源码分析】从源码角度去熟悉依赖注入(二)
【Spring源码分析】@Resource注入的源码解析
【Spring源码分析】循环依赖的底层源码剖析
【Spring源码分析】Spring的启动流程源码解析
【Spring源码分析】解析配置类-ConfigurationClassPostProcessor源码分析
【Spring源码分析】Spring之AOP底层源码解析和@Async源码解析

看这篇之前一定要看我的上一篇源码分析AOP的,这篇不会讲述AOP的内容,主要是分析对应的Advice。

透过源码看透Spring事务

  • 一、EnableTransactionManagement 注解如何开启声明事务的?
  • 二、TransactionInterceptor 源码分析
    • 开启事务源码分析
      • 开启事务 startTransaction 方法源码分析
    • 提交事务 commitTransactionAfterReturning 方法源码分析
    • 回滚 completeTransactionAfterThrowing 源码解析
  • 三、总结

有些人应该是不愿意看源码的,这里先直接放我总结的图吧,也是大家想知道的Spring的事务传播机制:

请添加图片描述

一、EnableTransactionManagement 注解如何开启声明事务的?

在配置类上配置 EnableTransactionManagement 这个注解会往容器中注入俩个Bean,一个是判断Spring创建Bean时找到容器的Advisor进行AOP,一个是对应的Advisor。

在这里插入图片描述在这里插入图片描述可以看见上面导入了 AutoProxyRegister 和 ProxyTransactionManagementConfiguration 这俩配置类。
AutoProxyRegister 配置类会向容器内注入 InfrastructureAdvisorAutoProxyCreator 这个BeanPostProcessor,它在Bean的初始化后阶段就会判断是否进行AOP,然后通过ProxyFactory去得到对应代理对象放入单例池中,这前面都有叙述,这篇不阐述。

在这里插入图片描述ProxyTransactionManagementConfiguration 会向容器内注入一个 Advisor,这个 Advisor 的 Pointcut 就是判断方法或者类上是否有 @Transaction 注解,有的话就符合要求:

在这里插入图片描述

二、TransactionInterceptor 源码分析

TransactionInterceptor 就是对应的 Advice,我们分析过 ProxyFactory 源码,当拿到代理对象去执行某方法的时候,就是先执行符合条件的 Advice 链,而 TransactionInterceptor 就是事务代理逻辑的一环,也是声明式事务背后的主要处理逻辑。

  1. 首先是获取到 @Transaction 注解的属性值然后封装成了一个 TransactionAttribute 对象;
    在这里插入图片描述

  2. 然后获取到容器内的 TransactionManager 数据库管理对象,应该为 PlatformTransactionManager 类型,从容器内获取到后强转为 PlatformTransactionManager 类型。
    在这里插入图片描述在这里插入图片描述

  3. 然后的话在 createTransactionIfNecessary 方法中进行开启事务,这里涉及到开启事务的整个过程,Spring提供的事务传播机制也是在这里进行实现那的,非常关键的方法;
    在这里插入图片描述

  4. 若没有其他AOP行为了的话,这一步就该执行目标方法了,就是去执行一堆SQL~

在这里插入图片描述

  1. 若执行目标方法这个过程抛出了异常,就尝试进行回滚,由于事务的传播机制的存在,回滚也有具体的逻辑的,不是直接回滚。
    在这里插入图片描述

  2. 如果没有异常发送的话,就提交事务,也是由于传播机制的存在,提交也不是瞎鸡儿提交的,有具体的逻辑。

在这里插入图片描述

下面的话就对开启事务、回滚、提交这三个逻辑进行具体分析。

开启事务源码分析

就是通过注入容器的 PlatformTransactionManager 去开启对应事务(开发中如果需要手动去开启事务,也是通过注入 PlalformTransactionManager#getTransaction 去是实现的)ka开始事务本身是一个简单的操作,但是由于扩展了事务传播机制,这个 getTransaction 也随之变的复杂起来了,分开解析。

  1. 若是首次开启事务,就是不存在事务内调用了另一个@Transaction 方法。这个时候若事务的传播机制是 Mandatory,那就直接抛出异常,这种事务传播机制不允许你首次开启事务;
    在这里插入图片描述

  2. 依旧是首次开启事务,若事务传播机制是 Require、Require_New、Nested ,就会调用 startTransaction 去开启一个事务(开启事务这个方法最后解析)
    在这里插入图片描述

  3. 若是已经在开启事务的基础上尝试开启事务,首先是会从ThreadLocal上下文中获取到对应数据库连接对象(这个在开启事务中会阐述,这里先知道一下),然后封装到 DataSourceTransactionObject 对象中,并设置 newConnectionHolder 这个标记为为false,表示不是自己创建的。

在这里插入图片描述

  1. 随后会根据上面那个返回的数据源对象去判断当前线程是否存在一个事务,如果存在就去执行 handleExistingTransaction 方法,去执行存在事务对应的逻辑
    在这里插入图片描述判断当前线程是否存在一个事务的逻辑,其实就是判断上面从上下文是否可以获取到对应的数据库连接对象

在这里插入图片描述

  1. 接下来执行对应存在事务对应的逻辑了

如果事务的传播机制是 Never 的话直接抛出异常:

在这里插入图片描述
如果事务传播机制是 Not_Supported 将事务进行挂起,然后正常去执行就好了(就是不受事务的传播机制所影响了)

在这里插入图片描述
如果事务传播机制是 Require_New ,挂起原本事务,然后新开启一个事务:

在这里插入图片描述
如果事务传播机制是 Nested ,则创建一个 savepoint ,正常使用此事务(如果使用的是 JTA 事务管理器就会新开启一个事务,和 Require_New 一样了都)

在这里插入图片描述若是其他事务传播机制,就正常去执行,仍然是在上一个事务基础上,这里说的是 Require、Support、Mandatory,Mandatory 是在第一次抛异常的,而这里是嵌入的 @Transaction,则仍然会继续执行。

在这里插入图片描述大致流程其实说完了,现在咱细看一下开启事务和挂起事务的源码

开启事务 startTransaction 方法源码分析

在这里插入图片描述doBegin 方法源码分析:

  1. 若当前事务没有创建数据库连接,则创建一个数据库连接对象
    在这里插入图片描述
  2. 设置一些参数,如:事务隔离级别、autoCommit、readOnly等等

在这里插入图片描述

  1. 将数据库连接绑定到上下文中,供后续调用

在这里插入图片描述在这里插入图片描述在这里插入图片描述

prepareSynchronization 方法解析:

该方法就是搞了个上下文标记当前线程是开启了事务的

在这里插入图片描述在这里插入图片描述在这里插入图片描述

提交事务 commitTransactionAfterReturning 方法源码分析

  1. 若配置了强制回滚就会直接回滚,不会提交

在这里插入图片描述

  1. 如果配置了 savepoint,就会把savepoint设置为空,表示已经后续回滚也和这个savepoint没关系了,就咱说嵌入Transaction然后事务的传播机制是 Nested 的时候;如果这是一个新的事务,那就会进行提交,新事务就是说第一次创建的,没另一个Transaction嵌入;

在这里插入图片描述

  1. 恢复挂起的资源到当前线程中,就是将之前挂起的status重新放入到resources上下文中
    在这里插入图片描述

回滚 completeTransactionAfterThrowing 源码解析

首先是判断抛出的异常是否符合我们配置的 rollbackFor,norollbackFor 规则,如果是不符合回滚规则的直接提交,否则走回滚逻辑:
在这里插入图片描述

  1. 如果设置了 savepoint 就回滚到 savepoint 的位置,这就是 Nested ,嵌入Transaction 时可能发生的情况

在这里插入图片描述

  1. 如果是新事务的话就直接回滚

在这里插入图片描述

三、总结

简单阐述这个切面 实现就是:开启事务->执行目标对象方法->提交/回滚

考虑到Spring搞了个事务传播机制,那就需要考虑传播机制带来的影响咯,默认是 Require 传播机制,理解为正常事务就好了。

直接看图吧:

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/507650.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java程序运行的问题——异常

什么是异常? Java程序在运行时出现的问题就叫异常 jdk中将异常一新封装成了一个个的类,当出现问题时,就会创建异常对象,抛出异常信息(问题原因、位置) 1.异常 1.1的继承体系 Throwable 是所有错误(erro…

关于OpenFeign的返回类型包装问题

在一天夜里。我在使用feign的调用时,突然出现了一点点问题。 就是对于feign类型的包装问题。产生了疑问。 在后来,也就是今天。在网上取取经。看到了一个答案。说:feign的调用会有一个编码器和解码器。 使用feign的解码器。他的原理也很简…

NineAi3.5 –支持GPT绘图,语音播报,联网访问,上下文关联,语音模式

NineAi3.5 –支持GPT绘图,语音播报,联网访问,上下文关联,语音模式 基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具,它能够通过学习和理解人类的语言来进行对话, 还能根据聊天的上下文进行互动&…

热门IT【视频教程】-华为/思科/红帽/oracle

华为认证 网络工程师-入门基础课:华为HCIA认证课程介绍-CSDN博客 网络工程师进阶课:华为HCIP认证课程介绍-CSDN博客 职场进阶,踏上高峰——HCIE-Datacom认证-CSDN博客 华为HCIA试听课程 : 超级实用,华为VRP系统文件…

4核8G服务器租用优惠价格418元一年,可买3年

京东云4C8G云服务器优惠价格418元1年、1899元三年,配置为:轻量云主机4C8G-180G SSD系统盘-5M带宽-500G月流量,京东云主机优惠活动 atengyun.com/go/jd 可以查看京东云服务器详细配置和精准报价单,活动打开如下图: 京东…

【Go】十四、封装、继承

文章目录 1、封装2、继承3、继承的注意点 1、封装 隐藏实现细节保证数据安全(控制变量或方法的访问范围,private) Go中实现封装: 结构体、字段的首字母小写(Java的private)提供一个工厂模式函数&#xf…

SpringBoot+uniApp宠物领养小程序系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码1.保存宠物信息代码2.提交订单信息代码3.查询评论信息代码 一、项目演示 项目演示地址: 视频地址 二、项目介绍 项目描述:这是一个基于SpringBootuniApp框架开发的宠物领养微信小程序系统。…

数据可视化-ECharts Html项目实战(9)

在之前的文章中,我们学习了如何在ECharts中编写气泡图,词云图。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点赞,谢谢。 数据可视化-ECharts Ht…

vue 文件下载

1.返回路径下载 注: 针对一些浏览器无法识别的文件格式(如pdf、xls、ppt)。可以直接在地址栏上输入URL即可触发浏览器的下载功能。 情况1 //地址栏输入文件URLwindow.location.href URLwindow.open(URL) 注:该方式将下载逻辑放在后端处理&#xff0c…

面试时如何回答接口测试怎么进行

一、什么是接口测试 接口测试顾名思义就是对测试系统组件间接口的一种测试,接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。 …

权限提升-Linux系统权限提升篇VulnhubCapability能力LD_Preload加载数据库等

知识点 1、Web或用户到Linux-数据库类型 2、Web或用户到Linux-Capability能力 3、普通用户到Linux-LD_Preload加载so配合sudo 章节点: 1、Web权限提升及转移 2、系统权限提升及转移 3、宿主权限提升及转移 4、域控权限提升及转移 基础点 0、为什么我们要学习权限…

Python接口自动化 —— 什么是接口测试、为什么要做接口测试?

简介 上一篇和大家一起科普扫盲接口后,知道什么是接口,接口类型等,对其有了大致了解之后,我们就回到主题-接口测试。 什么是接口测试 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各…

C语言-冒泡排序算法

题目描述 设计一个程序,实现冒泡排序算法,并输出{9,8,7,6,5,4,3,2,1,0} 的排序过程。 输出 每个排序过程输出一行,直到排序完成。 样例输出 Expected 9 8 7 6 5 4 3 2 1 0 0 9 8 7 6 5 4 3 2 1 0 1 9 …

HDLbits 刷题 -- Always if

学习: An if statement usually creates a 2-to-1 multiplexer, selecting one input if the condition is true, and the other input if the condition is false. always (*) beginif (condition) beginout x;endelse beginout y;end end This is equivalent …

衍生品交易概况

场内 场外 交易台架构 报价、交易、研究、程序个股、股指Flow、Exotic线性、非线性 对冲管理 管理风险敞口 做好情景分析 尊重市场选择 及时调整策略 理解头寸 善于学习 场外衍生品交易员的一天 盘前 回顾市场、决定今天总体方向处理隔夜敞口 盘中 处理客户询价…

关于 HEAP CORRUPTION DETECTED:after Normal block 错误的原因及解析

目录 一、HEAP CORRUPTION DETECTED:after Normal block 出现的报错情况: 二、问题原因(重要): 三、举例 1.错误代码如下: 2.错误原因及分析(重要): 3.解决方法 ​编辑 4.正…

两数之和-考察哈希表的运用

题目 给定一个整数数组 n u m s nums nums和一个整数目标值 t a r g e t target target,请你在该数组中找出和为目标值 t a r g e t target target的那 两个整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同…

计算机网络数据链路层知识总结

物理层知识总结传送门 计算机网络物理层知识点总结-CSDN博客 功能 功能概述 一些基本概念 结点:主机、路由器链路﹔网络中两个结点之间的物理通道,链路的传输介质主要有双绞线、光纤和微波。分为有线链路、无线链路。数据链路︰网络中两个结点之间的逻辑通道&a…

“数字化”持续走热,VR全景助力制造业上“云”

制造业要升级,数字化改造是重要途径。 早年间,由于对数字化的认识不足,一些企业明明有数字化改造需求,却不敢、不愿、不会上“云”。直到此次两会期间,2024年政府工作报告再次提出推动制造业数字化转型,越…