当前位置: 首页 > news >正文

Spring事务传播机制

目录

一、事务在Spring中是如何运作的

1.1 开启事务(DataSourceTransactionManager.doBegin)

二、Spring的事务传播机制

2.1 子事务的传播机制为REQUIRED

2.2 子事务的传播机制为REQUIRES_NEW

2.3 子事务的传播机制为NESTED


当我们在使用Spring所提供的事务功能时,如果是仅仅处理单个的事务,是比较容易把握事务的提交与回滚,不过一旦引入嵌套事务后,多个事务的回滚和提交就会变得复杂起来,各个事务之间是如何相互影响的,是一个值得讨论的点。

一、事务在Spring中是如何运作的

在了解嵌套事务之前,可以先看下单个事务在Spring中的处理流程,以便后面可以更清晰地认识嵌套事务的逻辑。

Spring事务使用AOP的机制实现,会在@Transactional注解修饰的方法前后分别织入开启事务的逻辑,以及提交或回滚的逻辑。@Transactional可以修饰在方法或者类上,区别就在于修饰于类上的,会对该类下符合条件的方法(例如private修饰的方法就不符合条件)前后都织入事务的逻辑。

具体的处理逻辑如下(具体的方法路径为TransactionInterceptor.invoke -> TransactionAspectSupport.invokeWithinTransaction):

1.1 开启事务(DataSourceTransactionManager.doBegin)

这里主要做了获取连接,并关闭自动提交,将@Transactional注解中的一些参数初始化到txObject对象中。

1.2 异常回滚(TransactionAspectSupport.completeTransactionAfterThrowing)

这里是事务异常回滚的地方,这里有个注意点是回滚会先用rollbackOn这个方法判断,默认情况下只有RunTimeException以及Error是会进行回滚的,除非在@Transactional显式声明了rollbackFor。

二、Spring的事务传播机制

当出现多个事务嵌套的场景发生时,Spring事务的处理会变得复杂一些,需要考虑嵌套事务下的提交顺序,以及回滚顺序。对此,Spring提供了多种的传播机制,每种传播机制的效果都不尽相同,以便应对各种复杂的业务场景。

正常处理的嵌套事务流程如下:

传播机制以及它们的效果如下:

REQUIRED:默认值,支持当前事务,如果没有事务会创建一个新的事务

SUPPORTS:支持当前事务,如果没有事务的话以非事务方式执行

MANDATORY:支持当前事务,如果没有事务抛出异常

REQUIRES_NEW:创建一个新的事务并挂起当前事务

NOT_SUPPORTED:以非事务方式执行,如果当前存在事务则将当前事务挂起

NEVER:以非事务方式进行,如果存在事务则抛出异常

NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作

以下的说明均建立在父事务的传播机制为REQUIRED的前提下,来探讨各种传播机制的回滚策略。

2.1 子事务的传播机制为REQUIRED

子事务

主事务

结果

异常

正常,并try-catch异常

均回滚

正常

异常

均回滚

正常

异常,并try-catch异常

不回滚

这里详细说下第一种场景,子事务异常情况下,主事务捕获了子事务的异常却仍发生了回滚。从代码来看:

回滚的原因在于,子事务失败的时候在回滚代码中设置了全局回滚的标识(AbstractPlatformTransactionManager.processRollback)。

之后主事务在进行事务提交时,会判断全局回滚标识是否存在。若存在就会进行回滚动作。(AbstractPlatformTransactionManager.commit)

2.2 子事务的传播机制为REQUIRES_NEW

子事务

主事务

结果

异常

正常,并try-catch异常

子回滚,主不回滚

正常

异常

子不回滚,主回滚

异常

正常

均回滚

这里主要说下第三种场景,因为从REQUIRES_NEW的描述中容易造成误解:创建一个新的事务并挂起当前事务,很容易理解为子事务独立于主事务,子事务回滚后不会影响主事务的执行。

我认为问题点主要在于对挂起的认识,可以看下Spring时如何执行的(AbstractPlatformTransactionManager.handleExistingTransaction):

在这个挂起动作中主要做了两件事,一是将全局ThreadLocal中的配置初始化,二是将原事务的信息保存在SuspendedResourcesHolder对象中。

当子事务异常回滚后,就会通过AbstractPlatformTransactionManager.resume方法恢复主事务。

恢复后,子会再向外抛出一个异常,因此主事务会接收到该异常,因此主事务也发生回滚。

总的来说,挂起的动作并不代表子完全独立于主。

2.3 子事务的传播机制为NESTED

子事务

主事务

结果

异常

正常,并try-catch异常

子回滚,主不回滚

正常

异常

均回滚

异常

正常

均回滚

NESTED是通过rollback的savepoint机制,实现异常回滚。相比于子事务为REQUIRED下,子事务异常,主事务try-catch了异常,REQUIRED情况下主子均会回滚,但NESTED模式主不会回滚。因此可以看下场景一,NESTED是如何处理的。

子事务如果是NESTED模式,则会保存savepoint,以便后面回滚到该savepoint。

回滚时,直接回滚到savepoint,且不会设置全局回滚标识。因此即相当于就是回滚了子事务。主事务由于try-catch了异常,因此执行方法的时候也没有抛出异常,正常走提交流程,且没有全局回滚标识,故不会回滚,正常提交。

PS: mysql的savepoint机制

BEGIN;

INSERT INTO test_entity values (1, ‘aaa’, 10); ①

SAVEPOINT savepoint1;

INSERT INTO test_entity values (2, ‘bbb’, 11); ②

ROLLBACK TO savepoint1;

RELEASE SAVEPOINT savepoint1;

COMMIT;

回滚到savepoint1,①会入库,②被回滚。

最后

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

小编已加密:aHR0cHM6Ly9kb2NzLnFxLmNvbS9kb2MvRFVrVm9aSGxQZUVsTlkwUnc==出于安全原因,我们把网站通过base64编码了,大家可以通过base64解码把网址获取下来。

相关文章:

  • 实现深度理解函数指针
  • C/C++常用预编译指令介绍
  • 杰理强制升级工具4.0使用和原理解析
  • Vue3介绍和安装
  • Linux命令--权限(chmod、chown)--使用/实例
  • flink-sql所有语法详解
  • 【图像分割】基于matlab萤火虫算法图像聚类分割【含Matlab源码 2106期】
  • SQL 入门之第一讲——MySQL 8.0.29安装教程(windows 64位)
  • 用Python进行数学建模(一)
  • 力扣:669. 修剪二叉搜索树,今日份快乐
  • java毕业设计KTV点歌系统mybatis+源码+调试部署+系统+数据库+lw
  • [python] 基于diagrams库绘制系统架构图
  • 2022 年全国职业院校技能大赛(中职组) 网络安全竞赛试题D模块评分标准
  • C++ 语法基础课1 —— 变量、输入输出、顺序语句
  • M的编程备忘录之C++——map和set
  • avalon2.2的VM生成过程
  • css布局,左右固定中间自适应实现
  • gcc介绍及安装
  • Java方法详解
  • js作用域和this的理解
  • nodejs调试方法
  • PAT A1120
  • PHP那些事儿
  • Python3爬取英雄联盟英雄皮肤大图
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • Spring-boot 启动时碰到的错误
  • Spring声明式事务管理之一:五大属性分析
  • Vue2.0 实现互斥
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Windows Containers 大冒险: 容器网络
  • 百度地图API标注+时间轴组件
  • 从0实现一个tiny react(三)生命周期
  • 基于web的全景—— Pannellum小试
  • 解决iview多表头动态更改列元素发生的错误
  • 精彩代码 vue.js
  • Java总结 - String - 这篇请使劲喷我
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • !!Dom4j 学习笔记
  • #vue3 实现前端下载excel文件模板功能
  • (6)设计一个TimeMap
  • (C语言)球球大作战
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (黑马C++)L06 重载与继承
  • (南京观海微电子)——I3C协议介绍
  • (一)基于IDEA的JAVA基础10
  • (转)Scala的“=”符号简介
  • (转)用.Net的File控件上传文件的解决方案
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • @column注解_MyBatis注解开发 -MyBatis(15)
  • @RequestMapping处理请求异常
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • [android] 看博客学习hashCode()和equals()