Spring底层事务原理

news2025/1/13 16:45:44

Spring事务底层原理

  • 一、@EnableTransactionManagement工作原理
  • 二、Spring事务基本执行原理
  • 三、Spring事务的过程
  • 四、Spring事务传播机制
  • 五、Spring事务传播机制分类
    • (1)案例分析、情况1
    • (2)案例分析、情况2
    • (3)案例分析、情况3
    • (4)案例分析、情况4
  • 六、Spring事务强制回滚
  • 七、TransactionSynchronization

在这里插入图片描述

一、@EnableTransactionManagement工作原理

开启Spring事务本质上就是增加了一个Advisor,但我们使用 @EnableTransactionManagement注解来开启Spring事务是,该注解代理的功能就是向Spring容器中添加了两个Bean:

1AutoProxyRegistrar2ProxyTransactionManagementConfiguration

(1)AutoProxyRegistrar
主要的作用是向Spring容器中注册了一个InfrastructureAdvisorAutoProxyCreator的Bean。
而InfrastructureAdvisorAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator,所以这个类的主要作用就是开启自动代理的作用,也就是一个BeanPostProcessor,会在初始化后步骤中去寻找Advisor类型的Bean,并判断当前某个Bean是否有匹配的Advisor,是否需要利用动态代理产生一个代理对象。

(2)ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

bean定义
BeanFactoryTransactionAttributeSourceAdvisor一个Advisor。
AnnotationTransactionAttributeSource相当于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut。就是用来判断某个类上是否存在@Transactional注解,或者判断某个方法上是否存在@Transactional注解的。
TransactionInterceptor相当于BeanFactoryTransactionAttributeSourceAdvisor中的Advice;就是代理逻辑,当某个类中存在@Transactional注解时,到时就产生一个代理对象作为Bean,代理对象在执行某个方法时,最终就会进入到TransactionInterceptor的invoke()方法。。

二、Spring事务基本执行原理

一个Bean在执行Bean的创建生命周期时,会经过InfrastructureAdvisorAutoProxyCreator的初始化后的方法,会判断当前Bean对象是否BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配逻辑为判断该Bean的类上是否存在@Transactional注解,或者类中的某个方法上是否存在@Transactional注解,如果存在则表示该Bean需要进行动态代理产生一个代理对象作为Bean对象。
该代理对象在执行某个方法时,会再次判断当前执行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法
执行基本流程为:

  1. 利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接
  2. 修改数据库连接的autocommit为false
  3. 执行MethodInvocation.proceed()方法,简单理解就是执行业务方法,其中就会执行sql
  4. 如果没有抛异常,则提交
  5. 如果抛了异常,则回滚

三、Spring事务的过程

1、数据库:建立连接、开启事务、进行sql操作、成功提交、失败回滚
2、业务逻辑:准备工作(可以进行前置通知)、开启事务、事务操作、成功提交(可以后置通知)、失败回滚(异常通知)
spring的事务是由aop实现的,首先要生成具体的代理对象,然后按照aop流程执行具体
的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务部署通过通知来实现的,
而是通过TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑。
步骤如下:
1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务。

2、当需要开启的时候获取数据库连接,关闭自动提交功能,开启事务。

3、执行具体的sql逻辑操作,在操作的过程中如果执行失败会通过 completeTransactionafterthrowing来完成事务的回滚操作,回滚的
具体逻辑是通过dorollback方法实现,实现时也要先获取连接对象,
然后通过连接对象进行回滚(conn.rollback)。

4、如果执行成功,那么通过completeTransactionafterrunning来完成事务的提交操作,
具体逻辑是通过docommit方法来实现,实现的时候也是先获取连接,通过连接对象来
进行提交(conn.commit)。

5、最后事务执行完毕需要清除事务相关的事务信息(cleanupTransactioninfo)。

四、Spring事务传播机制

在开发过程中,经常会出现一个方法调用另外一个方法,那么这里就涉及到了多种场景,比如a()调用b():

  1. a()和b()方法中的所有sql需要在同一个事务中吗?
  2. a()和b()方法中的所有sql需要在同一个事务中吗?
  3. a()需要在事务中执行,b()还需要在事务中执行吗?
  4. 或者其他情况
    这种情况下就要求Spring事务能支持上面各种场景,这就是Spring事务传播机制的由来。
    那Spring事务传播机制是如何实现的呢?

先描述其中一个场景中情况,a()在一个事务中执行,调用b()方法时需要新开一个事务执行:

  1. 代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a
  2. 将数据库连接a的autocommit改为false
  3. 把数据库连接a设置到ThreadLocal中
  4. 执行a()方法中的sql
  5. 执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)
  6. a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交

关于步骤5的一些详细解释:
1、代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线程其实已经拥有一个Spring事务了,则进行挂起
2、挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象中
3、挂起完成后,再次利用事务管理器新建一个数据库连接b
4、将数据库连接b的autocommit改为false
5、把数据库连接b设置到ThreadLocal中
6、执行b()方法中的sql
7、b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交
8、提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中

过程中最为重要的是在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

五、Spring事务传播机制分类

在这里面,以非事务方式运行,表示以非Spring事务运行,表示在执行这个方法时,Spring事务管理器不会去建立数据库连接,执行sql时,由Mybatis或JdbcTemplate自己来建立数据库连接来执行sql。

(1)案例分析、情况1

默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事务中执行。

@Component
public class UserService {
 	@Autowired
 	private UserService userService;

 	@Transactional
 	public void test() {
  		// test方法中的sql
  		userService.a();
 	}

 	@Transactional
 	public void a() {
  		// a方法中的sql
 	}
}

所以情况1的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、执行conn的commit()方法进行提交

(2)案例分析、情况2

如果是这种情况:

@Component
public class UserService {
 	@Autowired
 	private UserService userService;

 	@Transactional
 	public void test() {
  		// test方法中的sql
  		userService.a();
        int result = 100/0;
 	}

 	@Transactional
 	public void a() {
  		// a方法中的sql
 	}
}

所以情况2的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、抛出异常
6、执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉

(3)案例分析、情况3

@Component
public class UserService {
 	@Autowired
 	private UserService userService;

 	@Transactional
 	public void test() {
  		// test方法中的sql
  		userService.a();
 	}

 	@Transactional
 	public void a() {
  		// a方法中的sql
        int result = 100/0;
 	}
}

所以情况3的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、抛出异常
6、执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉

(4)案例分析、情况4

@Component
public class UserService {
 	@Autowired
 	private UserService userService;

 	@Transactional
 	public void test() {
  		// test方法中的sql
 	 	userService.a();
 	}

 	@Transactional(propagation = Propagation.REQUIRES_NEW)
 	public void a() {
  		// a方法中的sql
  		int result = 100/0;
 	}
}

所以情况3的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、又新建一个数据库连接conn2
5、执行a方法中的sql
6、抛出异常
7、执行conn2的rollback()方法进行回滚
8、继续抛异常,对于test()方法而言,它会接收到一个异常,然后抛出
9、执行conn的rollback()方法进行回滚,最终还是两个方法中的sql都回滚了

六、Spring事务强制回滚

正常情况下,a()调用b()方法时,如果b()方法抛了异常,但是a()方法捕获了,那么a()的事务还是会正常提交的,但是有的时候,我们捕获异常可能只是不把异常信息返回给客户端,而是为了返回一些更优良的错误信息,所以在这个时候,我们还是希望事务能回滚的,那就得告诉Spring把当前事务回滚掉,做法就是:

@Transactional
public void test(){
 
    // 执行sql
 	try {
  		b();
 	} catch (Exception e) {
  	// 构造友好的错误信息返回
  	TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 	}
    
}

public void b() throws Exception {
 	throw new Exception();
}

七、TransactionSynchronization

Spring事务有可能会提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监听当前Spring事务所处于的状态。

@Component
public class UserService {

 @Autowired
 private JdbcTemplate jdbcTemplate;

 @Autowired
 private UserService userService;

 @Transactional
 public void test(){
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

   @Override
   public void suspend() {
    System.out.println("test被挂起");
   }

   @Override
   public void resume() {
    System.out.println("test被恢复");
   }

   @Override
   public void beforeCommit(boolean readOnly) {
    System.out.println("test准备要提交");
   }

   @Override
   public void beforeCompletion() {
    System.out.println("test准备要提交或回滚");
   }

   @Override
   public void afterCommit() {
    System.out.println("test提交成功");
   }

   @Override
   public void afterCompletion(int status) {
    System.out.println("test提交或回滚成功");
   }
  });

  jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
  System.out.println("test");
  userService.a();
 }

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void a(){
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

   @Override
   public void suspend() {
    System.out.println("a被挂起");
   }

   @Override
   public void resume() {
    System.out.println("a被恢复");
   }

   @Override
   public void beforeCommit(boolean readOnly) {
    System.out.println("a准备提交");
   }

   @Override
   public void beforeCompletion() {
    System.out.println("a准备提交或回滚");
   }

   @Override
   public void afterCommit() {
    System.out.println("a提交成功");
   }

   @Override
   public void afterCompletion(int status) {
    System.out.println("a提交或回滚成功");
   }
  });

  jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
  System.out.println("a");
 }

}

在这里插入图片描述
记得一键三连哦!!!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SEVNLDAEFR, 186142-28-9

This peptide substrate corresponds to the Swedish Lys-Met/Asn-Leu (K670N/M671L) mutation of the amyloid precursor protein (APP) β-secretase cleavage site. It has been used for assaying β-secretase activity.该肽底物对应于淀粉样前体蛋白(APP) β-分泌酶切割位…

政企办公「分水岭」以至,融云百幄数智化破局

中国政企数智办公平台行业研究报告 246 年前,亚当斯密便在《国富论》中提出,劳动分工是提高社会生产效率的主要原因。从工厂定岗,到国际分工,分工的价值已经深入社会生活和工作的方方面面。关注【融云RongCloud】,了解…

六、使用注解开发

文章目录一、CRUD 注解(舍弃 mapper.xml): Select、 Insert、 Update、 Delete、 Param1、Select2、Insert3、Delete4、Update5、Param二、Lombok 插件,减少重复代码1、Data一、CRUD 注解(舍弃 mapper.xml): Select、 Insert、 Update、 Delete、 Param 通过注解去处…

【Netty】Netty高性能原理剖析

Netty高性能原理剖析1、前言2、Netty高性能2.1 多路复用通讯方式2.2 异步通讯 NIO2.3 零拷贝(DIRECT BUFFERS 使用堆外直接内存)2.4 内存池(基于内存池的缓冲区重用机制)2.5 高效的 Reactor 线程模型2.5.1 Reactor 单线程模型2.5.2 Reactor 多线程模型2.…

低代码有多爽?1个月的活,只需3天干完

仅看到“低代码”三个字,不少程序员就会吐槽“只适合简单业务,普通查改还行,复杂业务简直是灾难”,甚至认为是“儿童玩具”。 不少人自以为是程序员的二把刀,以为自己懂完了,在没理解低代码的应用场景&…

怎么压缩动态图片?手机怎么压缩gif动图?

在平时的聊天当中为了增加聊天的趣味性我们经常会保存一些有趣的gif动图表情包,但是由于gif图一般是由多帧组成,因此有的gif动图就会非常大,无法添加到表情当中,这时候就需要将gif压缩变小,那么我们用手机怎么压缩gif动…

华硕编程竞赛11月JAVA专场 C题太空遨游 题解

作者主页:Designer 小郑 作者简介:Java全栈软件工程师一枚,来自浙江宁波,负责开发管理公司OA项目,专注软件前后端开发(Vue、SpringBoot和微信小程序)、系统定制、远程技术指导。CSDN学院、蓝桥云…

chatGPT辣么火,你却不会注册

chatGPT 是什么? 一款目前超级火的 AI 对话聊天工具,只是不同于其他的智能聊天机器人那样,他非常的智能。 可以回答你的技术问题、帮你写代码、还能帮你写小说等等,发挥你的想象力,让他干点啥都行。 比如让他帮你用…

[附源码]Python计算机毕业设计SSM基于旅游服务平台(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

VMware使用和Linux安装Docker

一、VMware安装和配置 二、Linux安装Docker PS:记得每次配置安装新东西前先拍摄拍照,这样即使安装坏了,不需要重装虚拟机。(吃过这个亏) 1.Docker支持64位版本的CentOS 7和CentOS 8及更高版本,它要求Linux内核版本不…

Web前端大作业—— 饮食餐饮网站 咖啡网站pc端带轮播(5个页面)HTML+CSS+JavaScript 学生美食网页设计作品 学生餐饮文化网页模板

👨‍🎓静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计👩‍🎓,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等,用的最多的还是DW,当然不同软件写出的…

数据技术篇之日志采集

第2章 日志采集 1.日志采集有哪些 页面浏览日志 页面浏览日志是指当一个页面被浏览器加载呈现时采集的日志。此类日志 也是最基础的互联网日志,也是目前所有互联网产品的两大基本指标:页面浏览量(Page View,PV)和访客…

谈一谈 IPA 上传到 App Store Connect 的几种方法

谈一谈​ 1、前言​ 关于上传​ 2、Xcode​ 利用​ 3、Application Loader​ 当然,Xcode 这种方式,是需要有源代码情况下,才能上传。所以,就会有没有源代码的情况,怎么上传的情况啦!​ Application L…

ET框架解读其一

ECS? 真正的ECS属于是entity-component-system组件里面只有数据没有方法,system里面是针对组件的方法,system通过查找只需要关注自己想关注的组件集合就可以。但是ET框架的代码在组件里面写满了方法,有数据又有方法的组件&#x…

Spire.Doc for Java 10.12.2 update Word to PDF/HTML to Word

谷歌找破解版Spire.Doc for Java is a professional Word API that empowers Java applications to create, convert, manipulate and print Word documents without dependency on Microsoft Word. By using this multifunctional library, developers are able to process co…

并发编程概述 和 并行编程(Parallel Framework)

任务(task) 异步编程(async&await) 并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种…

HPPH-SiO2 NPs/PEG/DSPE光克洛修饰介孔二氧化硅纳米粒子/聚乙二醇/磷脂的研究

小编这里分享的科研知识是HPPH-SiO2 NPs/PEG/DSPE光克洛修饰介孔二氧化硅纳米粒子/聚乙二醇/磷脂的研究,来看! 光克洛修饰介孔二氧化硅纳米粒子的研究: 光敏剂的研发历经以卟吩姆钠为代表的第一代卟啉类光敏剂到以维替泊芬,他拉泊芬和替莫泊芬…

揭秘!女程序员为啥更赚钱?这4个大招,用Python做副业躺赚

关于穷,去年有了一个更学术的说法:隐形贫困人口。 就是因为有太多“种草达人”,让我们为了物质生活超前消费,再加上不理财的话,那简直是雪上加霜。 看到知乎上面最近有一个很火的问题: “90后的你&#…

为了学会更多炫酷的 canvas 效果,我熬夜复习了三角函数相关的知识点

稳定性建设之JavaScript代码不能被阻断 背景 js代码可能会因为某些原因,导致出错,进而整个后续代码有可能都被阻断。直接影响线上的稳定性 最常见的js被阻断的情况 console.log(111) // 预期 a {} // 结果 a undefined a.a 1 console.log(222) // …

web前端期末大作业 HTML游戏资讯网页设计制作 简单静态HTML网页作品 DW游戏资讯网页作业成品 游戏网站模板

🎉精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…