【Spring】事务实现原理

在使用事务的时候需要添加@EnableTransactionManagement注解来开启事务,Spring事务底层是通过AOP来实现的,所以启用事务后,同样会向容器中注入一个代理对象创建器,AOP使用的是AnnotationAwareAspectJAutoProxyCreator,事务使用的是InfrastructureAdvisorAutoProxyCreator。

  • Advice通知:定义在切点上需要执行什么样的操作;

  • PointCut切点:定义在哪些方法上使用通知;

  • Advisor:Advice和Pointcut加起来组成了Advisor,可以看做是对切面的封装;

在使用AOP时,一般会创建一个切面,里面包含了切点和通知,事务既然基于AOP实现,所以也会有对应的通知和切点。

事务Advisor

开启事务时,还会向Spring容器中注册一个BeanFactoryTransactionAttributeSourceAdvisor,从名字上可以看出它是一个Advisor,它重点有以下几个类型的成员变量:

  • Advice(通知):传入的实际类型为TransactionInterceptor,它是事务拦截器,实现了Advice接口,这个拦截器就相当于AOP中的通知,在执行目标方法前会进行拦截,进行事务处理;

  • TransactionAttributeSourcePointcut(切点):它实现了Pointcut和MethodMatcher接口,是一个切点,目标方法是否需要被事务代理就是通过它判断的;

  • TransactionAttributeSource:传入的实际类型为AnnotationTransactionAttributeSource,用于解析事务属性相关配置信息;

Advisor由Advice和Pointcut组成,现在Advice和Pointcut都已经知道了,接下来就去看看是如何判断当前Bean是否需要进行事务代理的。

事务底层是通过AOP实现的,所以它的处理逻辑与AOP类似,启动时会注册一个后置处理器,在postProcessAfterInitialization方法中判断是否需要进行代理,逻辑与AOP一致,会获取所有的Advisor,判断是否有匹配当前Bean的Advisor,Spring会自动为事务注册Advisor(BeanFactoryTransactionAttributeSourceAdvisor),匹配的处理逻辑在TransactionAttributeSourcePointcut切点中实现,是否匹配的判断条件如下:

  1. 判断当前Bean的Class是否匹配,具体是通过ClassFilter(TransactionAttributeSourceClassFilter)的matches方法实现的,注意这里并不是判断当前Bean所在类上面是否有事务注解,这个条件主要是为了排除一些Spring认为不需要进行事务代理的类,比如某个Bean的类路径以java.开头,而我们编写的类一般不会是以java开头的,所以这个Bean就会跳过代理,对于我们编写的Bean,一般不会被这个条件过滤掉,会进行下一个条件判断;

TransactionAttributeSourceClassFilter是TransactionAttributeSourcePointcut的内部类,里面有matches方法的实现。

  1. 判断当前Bean中的方法是否与事务切点匹配,具体是通过MethodMatcher(TransactionAttributeSourcePointcut)的matches方法实现,这里会获取当前Bean的所有方法,一个个与事务切点进行匹配,匹配规则如下:

(1)从方法中获取事务注解相关的设置;
(2)从方法所在类中获取事务注解相关设置;
(2)如果方法所在的类实现了接口,还会从接口上面解析是否有事务注解相关的配置;

如果我们使用了@Transactional注解对方法或者类进行了配置,就会在这一步解析到相关内容。

如果通过以上方式中的任意一种获取到了事务相关设置,就会认为当前Bean需要进行事务代理,为其创建代理对象,实现与AOP一致,会为其创建一个AOP代理对象,只不过在执行目标方法时,Spring会通过已经设定好的事务切面进行拦截,也就是BeanFactoryTransactionAttributeSourceAdvisor中的TransactionInterceptor对进行方法拦截,而在AOP中一般是我们自己编写切面。

事务拦截

上面我们知道对于需要进行事务拦截的Bean,会为其创建代理对象,在执行目标方法的时候,会进入事务拦截器的处理逻辑,主要步骤如下:

  1. 获取事务管理器;
  2. 创建事务;
  3. 这里主要是向后执行拦截器链,待所有的拦截器都执行完毕之后,执行目标方法;
  4. 捕捉异常,如果出现异常进行回滚;
  5. 提交事务;

事务的创建

事务的创建分为两部分:

一、 获取事务

(1)首先获取事务对象,它是一个抽象方法,数据源的不同具体的实现类也不同;

以DataSourceTransactionManager为例,它主要是创建了一个数据源事务对象(DataSourceTransactionObject),然后根据数据源信息源获取当前线程绑定的ConnectionHolder对象(如果有的话会获取到否则获取为空),ConnectionHolder中存有数据库连接及事务的活跃状态,之后会将这个ConnectionHolder设置到数据源事务对象中,将数据源事务对象返回;

(2)根据上一步获取到的事务对象,判断当前线程是否存在事务,如果存在事务需要根据事务传播行为进行不同的处理;

是否存在事务的判断方式是通过当前线程是否持有数据库连接(数据源事务对象中的ConnectionHolder不为空)并且事务处于活跃状态。

  • 如果事务传播行为设是PROPAGATION_NEVER,表示不能存在事务,当前存在事务会抛出异常;
  • 如果事务的传播行为是PROPAGATION_NOT_SUPPORTED,表示以不使用事务的方式执行,如果当前存在事务,则挂起当前的事务,执行完当前逻辑后(不使用事务)再恢复挂起的事务;
  • 如果事务的传播行为是PROPAGATION_REQUIRES_NEW,表示每次执行都新建事务,如果当前存在事务需要挂起当前事务,创建一个自己的事务执行之后再恢复挂起的事务;
  • 如果事务的传播行为是PROPAGATION_NESTED,表示嵌套事务,判断是否使用保存点,如果是则使用嵌套事务,否则开启一个新事务;
  • 其他情况使用当前的事务;

(3)如果当前线程不存在事务:

  • 如果事务的传播行为是PROPAGATION_MANDATORY,它要求必须存在事务,当前不存在事务,会抛出异常;

  • 如果传播行为是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED,新建事务;

  • 其他情况创建一个空事务;

新建事务说明之前不存在事务,ConnectionHolder为空,此时会从数据库连接池中获取一个连接,设置到ConnectionHolder中,并将当前线程对应这个ConnectionHolder与数据源绑定(底层ThreadLocal实现),上面第(1)步中可以看到会通过数据源获取当前线程的ConnectionHolder,数据就是在这里添加的,之后就可以通过这个判断当前线程是否已经存在事务。

二、 预处理事务

主要是进行事务相关信息的封装以及事务和线程的绑定。

事务回滚

当执行过程中出现异常时,会进行事务回滚,回滚的处理逻辑如下:

  1. 判断事务是否设置了保存点,如果设置了将事务回滚到保存点;
  2. 如果是一个独立的新事务,直接回滚即可;
  3. 如果既没有设置保存点,也不是一个新事务,说明可能处于嵌套事务中,此时只设置回滚状态rollbackOnly为true,当它的外围事务进行提交时,如果发现回滚状态为true,外围事务则不提交;
资源清理

在事务提交/回滚之后,需要根据情况清理相关的资源以及恢复被挂起的事务,主要有以下操作:

  1. 清除当前线程绑定的事务相关信息;
  2. 清除当前线程对应的ConnectionHolder与数据源的绑定关系及ConnectionHolder自身的清理;
  3. 如果挂起的事务不为空,恢复挂起的事务;

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

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

相关文章

易点易动固定资产管理系统:实现财务与OA系统的无缝对接,高效管理固定资产

在现代企业经营中,固定资产管理是一个非常重要的环节。准确记录和管理固定资产不仅对企业的财务状况有直接影响,还能提高资产利用率、降低运营成本,并确保企业的合规性。然而,传统的固定资产管理方式往往存在繁琐、效率低下的问题…

计算机考研408到底有多难?25届开个好头很有必要

前言 大家好,我是陈橘又青,相信关注我的各位小伙伴们中,大多都是在计算机专业的大学生吧! 每天都有许多人在后台私信我,问我要不要考研,我想说这个东西是因人而异的,像我本人就选择了就业&…

ADS微带单枝短截线匹配电路的仿真

ADS微带单枝短截线匹配电路的仿真 简介环境原理图过程版图过程 简介 利用ADS2020软件设计匹配电路通常有5种方法,本小节首先介绍如何通过“Design-Guide”进行微带单枝短截线匹配电路的设计与仿真。 环境 ADS2020 《ADS2011射频电路设计与仿真实例》 [徐兴福著][…

10 个适用于 Windows 的最佳 PDF 编辑器,用于轻松编辑 PDF 文件

PDF 是当今最流行的文件格式之一。Adobe 于 1993 年开发了 PDF 文件格式。PDF(便携式文档格式)主要用于存储复杂的文本文档和电子书。PDF 文件包含固定的布局属性,并且可以存储大量文本和图形。PDF 文件格式主要用于分发大型文档。 使用 PDF…

vmware16.2内部win7联网

1、主机配置 前置条件:DHCP和NAT服务已启动 设置无线IP与虚拟机IP为自动获取 二者都是:右键-属性 选择IPv4 自动获取 2、虚拟机配置 设置虚拟机上网方式为NAT 菜单栏-虚拟机-设置 NMnet8改为NAT模式 菜单栏-编辑-虚拟网络编辑器 win7系统内部网…

Linux设置N天未登录强制冻结

1、创建普通用户 2、90天未登录强制冻结 chage -E $(date -d "90 days" %Y-%m-%d) 用户名 3.更改系统日期 sudo date -s "2024-02-07 20:18:00" 4.过期未登录,提示如下 5.账号解冻 chage -E -1 用户名

Apinto 网关进阶教程,使用 API Mock 生成模拟数据

什么是 API Mock ? API Mock 是一种技术,它允许程序员在不依赖后端数据的情况下,模拟 web服务器端 API 的响应。通常使用 API Mock 来测试前端应用程序,而无需等待后端程序构建完成。API Mock 可以模拟任何 HTTP 请求方法&#x…

【操作系统】测试二

文章目录 单选题判断题填空题 单选题 在操作系统中,进行资源分配、调度和管理的最小独立单位是()。 【 正确答案: C】 A. 作业 B. 程序 C. 进程 D. 用户 进程在发出I/O请求后,可能导致下列哪种进程状态演变? 【 正确答…

MATLAB中Line 属性说明

目录 颜色和样式 位置 Line 属性是注释线条的外观和行为。 Line 属性控制 Line 对象的外观和行为。通过更改属性值,可以修改线条的特定方面。使用圆点表示法查询和设置属性。 h annotation("line"); c h.Color; h.Color "red"; 颜色和样…

【23真题】太难!千万别考!不值!

今天分享的是23年哈尔滨工程大学810的信号与系统试题及解析。 为什么说不值呢?因为哈工程810据之前的分析来看不保护一志愿,就23年810的专业课来看,又在超纲的边缘疯狂试探!(如果它默认考DSP,当我没说&…

单源最短路的简单应用

1.dijkstra维护最长路 下面这个是讨论区的一个佬的理解,非常的nice 总结一句话,dijkstra的贪心保证了每次选定的点在之后都不会被其他点所更新了 同理维护最长路的时候我们发现,如果权值是0-1的话,选定的最大值在之后不会变的更大…

跨链知识指南

跨链知识指南 什么是跨链 跨链就是能够让两个不同的链产生某种关联的技术,或者说能把链A的东西搬到链B,跨链是一个复杂的过程,需要链对链外的信息的获取与验证,需要节点有单独的验证能力等等 什么是跨链桥? 跨链桥…

凯美瑞 vs 太空船:Web3 游戏生长的两条路径

撰文:Teng Yan(0xPrismatic),Delphi Digital 研究员 编译:TinTinLand 来源:https://0xprismatic.substack.com/p/my-short-web3-gaming-thesis 经常有人问我关于 Web3 游戏的看法,所以我想以这…

实时时钟和日历电路MS85163/MS85163M

主要特点 ◼ 基于 32.768kHz 晶振提供年、月、日、 周工作日、小时、分钟和秒 ◼ 具有世纪标记,可工作于 2000-2199 年 ◼ 工作电压: 1.8V-5.5V ◼ 低功耗 ◼ 最高频率达 400kHz 的 I 2 C 接口 ◼ 可编程的时钟输出 (32.768kHz, 1.024kHz…

springcloud二手交易平台系统源码

开发技术: 大等于jdk1.8,大于mysql5.5,idea(eclipse),nodejs,vscode(webstorm) springcloud springboot mybatis vue elementui mysql 功能介绍: 用户端&…

JWFD开源工作流-随机函数发生器最新进展

使用WIN7 32位,JDK1.8平台,跑语法分析,实测结果如上图,比JDK1.6的每个函数计算速度快了不止100倍,升级为JDK1.8是正确的选择,这个模块是典型的变形函数计算单元,可以解决很多需要动态变形物理模…

【PyQt学习篇 · ⑪】:QPushButton和QCommandLinkButton的使用

文章目录 构造函数菜单设置扁平化默认处理右键菜单QCommandLinkButton的使用 构造函数 QPushButton的构造函数如下: """QPushButton(parent: Optional[QWidget] None)QPushButton(text: Optional[str], parent: Optional[QWidget] None)QPushButt…

hosts文件地址

Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址&…

python教程:把多张图片,合并成一张图

D:\Wdpython\environment\Scripts\python.exe D:/Wdpython/爬虫/测试8.py 图片列表 10 [‘刘亦菲/刘亦菲_1.jpg’, ‘刘亦菲/刘亦菲_11.jpg’, ‘刘亦菲/刘亦菲_12.jpg’, ‘刘亦菲/刘亦菲_13.jpg’, ‘刘亦菲/刘亦菲_15.jpg’, ‘刘亦菲/刘亦菲_2.jpg’, ‘刘亦菲/刘亦菲_3.jp…

[sd_scripts]之fine_tune

https://github.com/kohya-ss/sd-scripts/blob/main/docs/fine_tune_README_ja.mdhttps://github.com/kohya-ss/sd-scripts/blob/main/docs/fine_tune_README_ja.md fine-tune微调是指使用图像和文本对来训练模型,不包括lora、textual inversion和hypernetwork。 …
最新文章