首页 > 编程语言 >Spring事务底层源码解析(二)

Spring事务底层源码解析(二)

时间:2024-10-23 20:18:17浏览次数:3  
标签:事务 执行 Spring 数据库 PROPAGATION 源码 解析 方法 连接

今天根据具体的业务代码场景去分析spring事务的源码流程,其中事务传播属性还是PROPAGATION_REQUIRED

首先看下第一种业务场景,testTransaction1方法上加了@Transactionl注解,注解中调用了insertTransactionOne(),insertTransactionTwo()方法,这两个方法上面也都加了@Transactionl注解

首先看testTransaction1()方法,上节已经说了会创建数据库连接connection并与ThreadLocal绑定,此时事务状态newTransaction=true,表示这是新开启的事务。这些流程上节已经看过了,再看方法transactionOne.insertTransactionOne(),这个时候同样要去开启事务执行到了getTransaction方法中从ThreadLocal中获取数据库连接,此时就会判断isExistingTransaction方法,明显是存在的,就会去执行handleExistingTransaction方法

handleExistingTransaction方法的主要功能:

1、如果当前被调用的方法insertTransactionOne的事务传播属性为PROPAGATION_NESTED,那么就会将testTransaction1方法开启的事务挂起。

2、如果当前被调用的方法insertTransactionOne的事务传播属性为PROPAGATION_REQUIRED,那么就会将newTransaction属性设置为false,这个留意后面提交事务的时候有使用,然后就会去调用insertTransactionOne的原始方法,可以看到当前insertTransactionOne跟testTransaction1是在同一个事务中了。

当testTransaction1()方法执行完毕进行commit方法的时候,这里因为status.isNewTransaction为false,所以并不会执行testTransaction1方法的提交操作。

同理,执行完insertTransactionOne方法之后,继续执行insertTransactionTwo方法,流程跟insertTransactionOne相同,当这两个方法执行完毕的时候,那么就又回到了testTransaction1方法,此时他的newTransaction为true,那么就会执行doCommit方法将事务进行提交。

第二种基本场景,testTransaction2方法中,假如insertTransactionOne方法执行成功,insertTransactionTwo方法抛出异常

抛出异常之后会进到completeTransactionAfterThrowing方法,这里会

由于testTransaction2方法的isNewTransaction为false,所以不会执行回滚动作,但是将connectionHolder的rollbackOnly属性设置为了true。

insertTransaction2抛出异常后回到了testTransaction方法的执行逻辑,此时会再次进入到completeTransactionAfterThrowing方法,由于testTransaction的事务状态newTransaction为true,那么最终会执行con.rollback方法进行事务回滚操作。所以rollbackOnly属性是事务回滚操作中比较重要的属性

第三种基本场景,事务传播属性依然是PROPAGATION_REQUIRED;insertTransactionOne方法执行成功,但是insertTransactionTwo抛出异常,但是此时异常被捕获到,那么此时insertTransactionOne插入的数据会回滚吗?答案是肯定的。

关键属性其实还是rollbackOnly,insertTransactionTwo由于抛出异常了,会调用completeTransactionAfterThrowing方法将rollbackOnly更新为true,然后异常抛出,那么此时testTransaction3中的方法捕获到异常。

此时回到了testTransaction3方法的执行流程,且newTransaction属性为true,那么就会正常执行commitTransactionAfterReturning方法,这个时候判断rollbackOnly为true

由于testTransaction3的当前事务状态newTransaction为true,此时事务回滚。

第四种基本场景,事务传播属性依然是PROPAGATION_REQUIRED;这种场景是insertTransactionOne方法正常执行,insertTransactionTwo方法执行报错但是内部将异常进行捕获,并没有抛出来,此时的结论是insertTransactionOne方法事务提交,insertTransactionTwo方法没有插入数据。

原因就是insertTransactionTwo方法自己将事务给捕获了,没有进入到spring中的catch方法里面,那就不会执行到completeTransactionAfterThrowing方法,因此也就不会将rollbackonly设置为true,因此testTransaction4方法正常提交。

以上就是事务传播属性还是PROPAGATION_REQUIRED的主要流程。

接下来看另外一场常见的事务传播机制PROPAGATION_REQUIRED_NEW(新建事务,如果当前存在事务,把当前事务挂起)

在开发过程中,经常会出现一个方法调用另外一个方法,那么这里就涉及到了多种场景,比如a()调用b():
1. a()和b()方法中的所有sql需要在同一个事务中吗?
2. a()和b()方法需要单独的事务吗?
3. a()需要在事务中执行,b()还需要在事务中执行吗?
4. 等等情况...
所以,这就要求Spring事务能支持上面各种场景,这就是Spring事务传播机制的由来。那Spring事务PROPAGATION_REQUIRED_NEW传播机制是如何实现的呢?假如方法a()在一个事务中执行,a中调用了b方法,调用b()方法时需要新开一个事务执行:
1. 首先,代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a
2. 将数据库连接a的autocommit改为false
3. 把数据库连接a设置到ThreadLocal中
4. 执行a()方法中的sql
5. 执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)
i. 代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线
程其实已经拥有一个Spring事务了,则进行挂起
ii. 挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象

iii. 挂起完成后,再次利用事务管理器新建一个数据库连接b
iv. 将数据库连接b的autocommit改为false
v. 把数据库连接b设置到ThreadLocal中
vi. 执行b()方法中的sql
vii. b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交
viii. 提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存
的数据库连接a再次设置到ThreadLocal中
6. a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交
这个过程中最为核心的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

方法a第一次执行的时候,正常开启事务,流程与PROPAGATION_REQUIRED是一样的,关键流程是执行方法b()的时候,判断是存在数据库连接对象的、那么就会执行到handleExistingTransaction方法,做事务挂起操作。

suspend方法就是把ThreadLocal中的数据库连接从ThreadLocal中移除,并放入一个挂起资源对象 中,最终返回的suspendedResources就是持有了上个方法事务的连接,调用b方法这个时候就会重新调用startTransaction方法开启新的事务,也就是会创新新的连接。

b()方法开启新事务有两个关注的点:

1、newTransaction属性为true,就说明这是一个新的事务,当b方法执行到提交的时候就会真正提交;如果传播属性是PROPAGATION_REQUIRED,此时b方法这个属性应该为false,就表名方法b没有开启新事务,复用a方法的事务,最终提交由a方法提交

2、新创建的DefaultTransactionStatus方法的suspendedResources不为空,就是刚刚持有a()方法数据库连接的挂起资源对象;如果如果传播属性是PROPAGATION_REQUIRED,这个suspendedResources就是null,因为不会有挂起操作。这个对象在执行完b方法事务提交后,恢复a方法事务的时候需要用到,因此需要拿到a方法的连接。

b方法事务提交流程就跟PROPAGATION_REQUIRED也没什么区别,不过会有一个挂起事务恢复的操作,执行完b方法的事务提交之后,会走到cleanupAfterCompletion方法,由于当前事务的suspendedResources不为空,就会执行resume方法

这里会将挂起资源的数据库连接与当前线程ThreadLocal做一个重新绑定的操作,然后继续去执行a()方法的业务,如果此时a()方法执行失败,那么不会回滚b方法的事务。

Spring事务强制回滚操作:

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

最后一种事务传播属性PROPAGATION_NESTED(如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作),这种传播属性比较简单,其实就是利用数据库连接对象,在事务中设置一个savepoint,后续可以只回滚到某个savepoint。

标签:事务,执行,Spring,数据库,PROPAGATION,源码,解析,方法,连接
From: https://blog.csdn.net/qq_40228720/article/details/143156381

相关文章

  • spring boot整合Swagger
    你可能尝试过写完一个接口后,自己去创建接口文档,或者修改接口后修改接口文档。多了之后,你肯定会发生一个操作,那就是忘记了修改文档或者创建文档(除非你们公司把接口文档和写接口要求得很紧密......
  • vue3+java基于Spring Boot的爱老助老服务平台源码 lw 部署
    目录功能介绍具体实现截图技术介绍开发核心技术介绍:技术创新点vue3和vue2的区别:核心代码部分展示非功能需求分析系统开发流程软件测试源码获取功能介绍爱老助老服务平台的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使......
  • 《深度学习》YOLO V3 网络构架解析
    目录一、YOLOV3 1、了解YOLOv32、3个scale3、残差连接二、YOLOv3核心网络构架1、核心网络构架2、输入映射到输出3、先验框设计4、softmax层替代一、YOLO系列V3 1、了解YOLOv3        相比于YOLOv1和v2,YOLOv3最大的改进就是网络结构,使其更适合小目标......
  • C语言趣味编程100例源码分享
    C语言趣味编程100例是学习路上必不可缺的示例,话不多说直接看代码1,百钱百鸡问题include<stdio.h>main(){intcock,hen,chicken;for(cock=0;cock<=20;cock++) /外层循环控制公鸡数量取值范围0~20/for(hen=0;hen<=33;hen++) /内层循环控制母鸡数量取值范围0~30/for(chic......
  • Spring Boot 替换Word模板生成Word文件教程
    ......
  • springboot062购物推荐网站的设计与实现(论文+源码)_kaic
    东大每日推购物推荐网站的设计与实现摘要随着信息互联网购物的飞速发展,一般企业都去创建属于自己的电商平台以及购物管理系统。本文介绍了东大每日推购物推荐网站的开发全过程。通过分析企业对于东大每日推购物推荐网站的需求,创建了一个计算机管理东大每日推购物推荐网站的......
  • Springboot异步事件配置和使用
    Spring中提供了完整的事件处理机制,本身底层内置实现了一些事件和监听,同时支持开发者扩展自己的事件和监听实现。一般这种基于事件的实现在项目实际开发中我们主要用来解耦,和做异步处理(默认是同步),提供应用的响应速度。核心架构先简要看一下,在Spring中要实现自定义事件监听需要......
  • 第一个Java spring boot demo运行
     一、环境准备1,下载JavaJDK需要安装两个JDK版本:1.8/17安装ZuluJDK(不能使用OracleJDK)JDK17:https://www.azul.com/downloads/?version=java-17-lts&os=macos&package=jdk#zuluJDK8:https://www.azul.com/downloads/?version=java-8-lts&os=macos&package=jdk#zul......
  • 基于卷积神经网络的瓶盖状态识别系统,resnet50,mobilenet模型【pytorch框架+python源码
    更多目标检测和图像分类识别项目可看我主页其他文章功能演示:卷积神经网络,瓶盖状态识别系统,resnet50,mobilenet【pytorch框架,python】_哔哩哔哩_bilibili(一)简介基于卷积神经网络的瓶盖状态识别系统是在pytorch框架下实现的,这是一个完整的项目,包括代码,数据集,训练好的模型权重,......
  • 全方位解析直播美颜SDK:打造高效视频美颜平台的技术路径详解
    今天,小编将深入讲解直播美颜SDK的核心技术、架构设计和应用场景,帮助开发者理解如何构建高效的视频美颜平台。 一、直播美颜SDK的核心技术直播美颜SDK其核心功能包括实时美颜、磨皮、祛斑、瘦脸和眼部美化等。这些技术通常结合深度学习算法,通过对用户面部特征的实时分析,快速应用美......