Spring-事务管理-加强
目录
开启事务
编程式事务
声明式事务
声明式事务的优点
声明式事务的粒度问题
声明式事务用不对容易失效
Spring事务失效可能是哪些原因
@Transactional(rollbackFor = Exception.class)注解
Spring 事务的实现原理
事务传播机制
介绍
用法
rollbackFor
场景举例
事务接口
-
开启事务
- 事务管理在系统开发中是不可缺少的一部分,Spring提供了很好的事务管理机制,主要分为编程式事务和声明式事务两种
-
编程式事务
- 基于底层的API,如PlatformTransactionManager、TransactionDefinition 和 TransactionTemplate 等核心接口,开发者完全可以通过编程的方式来进行事务管理
- 编程式事务方式需要开发者在代码中手动的管理事务的开启、提交、回滚等操作

- 如以上代码,开发者可以通过API自己控制事务
-
声明式事务
- 声明式事务管理方法允许在开发者配置的帮助下来管理事务,而不需要依赖底层API进行硬编码
- 开发者可以只使用注解或基于配置的 XML 来管理事务

- 如上,使用@Transactional 即可给test方法增加事务控制
-
声明式事务的优点
- 通过上面的例子,其实我们可以很容易的看出来,声明式事务帮助我们节省了很多代码,他会自动帮我们进行事务的开启、提交以及回滚等操作,把程序员从事务管理中解放出来
- 声明式事务管理是使用了 AOP 实现的,本质就是在目标方法执行前后进行拦截
- 在目标方法执行前加入或创建一个事务,在执行方法执行后,根据实际情况选择提交或是回滚事务
- 使用这种方式,对代码没有侵入性,方法内只需要写业务逻辑就可以了
- 但是,声明式事务真的有这么好么?倒也不见得
-
声明式事务的粒度问题
- 首先,声明式事务有一个局限,那就是他的最小粒度要作用在方法上
- 也就是说,如果想要给一部分代码块增加事务的话,那就需要把这个部分代码块单独独立出来作为一个方法
- 但是,正是因为这个粒度问题,本人并不建议过度的使用声明式事务
- 首先,因为声明式事务是通过注解的,有些时候还可以通过配置实现,这就会导致一个问题,那就是这个事务有可能被开发者忽略
- 事务被忽略了有什么问题呢?
- 首先,如果开发者没有注意到一个方法是被事务嵌套的,那么就可能会在方法中加入一些如RPC远程调用、消息发送、缓存更新、文件写入等操作
- 我们知道,这些操作如果被包在事务中,有两个问题:
- 1、这些操作自身是无法回滚的,这就会导致数据的不一致;可能RPC调用成功了,但是本地事务回滚了,可是RPC调用无法回滚了
- 2、在事务中有远程调用,就会拉长整个事务;那么就会导致本事务的数据库连接一直被占用,那么如果类似操作过多,就会导致数据库连接池耗尽
- 有些时候,即使没有在事务中进行远程操作,但是有些人还是可能会不经意的进行一些内存操作,如运算
- 或者如果遇到分库分表的情况,有可能不经意间进行跨库操作
- 但是如果是编程式事务的话,业务代码中就会清清楚楚看到什么地方开启事务,什么地方提交,什么时候回滚
- 这样有人改这段代码的时候,就会强制他考虑要加的代码是否应该在方法事务内
- 有些人可能会说,已经有了声明式事务,但是写代码的人没注意,这能怪谁
- 话虽然是这么说,但是我们还是希望可以通过一些机制或者规范,降低这些问题发生的概率
- 比如建议大家使用编程式事务,而不是声明式事务
- 因为有些时候,声明式事务确实不够明显
-
声明式事务用不对容易失效
- 除了事务的粒度问题,还有一个问题那就是声明式事务虽然看上去帮我们简化了很多代码,但是一旦没用对,也很容易导致事务失效
- 如以下几种场景就可能导致声明式事务失效:
- 1、@Transactional 应用在非 public 修饰的方法上
- 2、@Transactional 注解属性 propagation 设置错误
- 3、@Transactional 注解属性 rollbackFor 设置错误
- 4、同一个类中方法调用,导致@Transactional 失效
- 5、异常被catch捕获导致@Transactional 失效
- 6、数据库引擎不支持事务
- 以上几个问题,如果使用编程式事务的话,很多都是可以避免的
- 使用声明式事务失效的问题,如:
- 因为Spring的事务是基于AOP实现的,但是在代码中,有时候我们会有很多切面,不同的切面可能会来处理不同的事情,多个切面之间可能会有相互影响
- 在之前的一个项目中,发现Service层的事务全都失效了,一个SQL执行失败后并没有回滚,排查下来才发现,是因为新增了一个切面,这个切面里面做个异常的统一捕获,导致事务的切面没有捕获到异常,导致事务无法回滚
- 很多人还是会说,说到底还是自己能力不行,对事务理解不透彻,用错了能怪谁
- 但是还是那句话,我们确实无法保证所有人的能力都很高,也无法要求所有开发者都能不出错
- 我们能做的就是,尽量可以通过机制或者规范,来避免或者降低这些问题发生的概率
- 其实,如果大家有认真看过阿里巴巴出的那份Java开发手册的话,其实就能发现,其中的很多规约并不是完完全全容易被人理解,有些也比较生硬,但是其实,这些规范都是从无数个坑里爬出来的开发者们总结出来的
- 关于@Transactional 的用法,规约中也有提到过,只不过规约中的观点没有这么鲜明

-
Spring事务失效可能是哪些原因
- Spring中比较容易失效的就是通过@Transactional 定义的声明式事务,他在以下几个场景中会导致事务失效,一定要注意:
- 1、@Transactional 应用在非 public 修饰的方法上

- private方法,只会在当前对象中的其他方法中调用,也就是会进行对象的自调用,这种情况是用this调用的,并不会走到代理对象,而@Transactional 是基于动态代理实现的,所以代理会失效
- 2、@Transactional 注解属性 propagation 设置错误

- 以上,如果事务发生回滚,则methodA并不会回滚
- 因为他的propagation是不支持事务,那么他就不会一起回滚
- 3、@Transactional 注解属性 rollbackFor 设置错误

- 以上,如果发生非RuntimeException,则事务不会回滚,那么就会导致事务失效
- 所以需要指定为 (rollbackFor = Exception.class)
- 4、同一个类中方法调用,导致@Transactional 失效

- 以上,和private是一回事,因为没办法走到代理服务,所以事务会失效
- 5、异常被catch捕获导致@Transactional 失效

- 以为异常被捕获,所以就没办法基于异常进行rollback了,所以事务会失效
- 6、数据库引擎不支持事务这个好理解,如myisam,不支持的肯定就不行了
-
@Transactional(rollbackFor = Exception.class)注解
- Exception分为运行时异常RuntimeException和非运行时异常
- 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性
- 当 @Transactional 注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义
- 如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚
- 在 @Transactional 注解中如果不配置 rollbackFor 属性,那么事物只会在遇到 RuntimeException 的时候才会回滚,加上 rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚
-
Spring 事务的实现原理
- Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是无法提供事务功能的
- 真正的数据库层的事务提交和回滚是通过binlog或者 redo log 实现的
- 编程式事务管理使用 TransactionTemplate
- 声明式事务管理是建立在 AOP 之上的
- 其本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务
- 声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional 注解的方式,便可以将事务规则应用到业务逻辑中
- 声明式事务管理要优于编程式事务管理,这正是 Spring 倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持
- 唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别
-
事务传播机制
-
介绍
- Spring的事务传播机制用于控制在多个事务方法相互调用时事务的行为
- 在复杂的业务场景中,多个事务方法之间的调用可能会导致事务的不一致,如出现数据丢失、重复提交等问题,使用事务传播机制可以避免这些问题的发生,保证事务的一致性和完整性
- Spring的事务规定了7种事务的传播级别,默认的传播机制是REQUIRED
- required,如果不存在事务则开启一个事务,如果存在事务则加入之前的事务,总是只有一个事务在执行
- required_new,每次执行新开一个事务
- supported,有事务则加入事务,没有事务则普通执行
- not_supported,有事务则暂停该事务,没有则普通执行
- mandatory,强制有事务,没有事务则报异常
- never,有事务则报异常
- nested,如果之前有事务,则创建嵌套事务,嵌套事务回滚不影响父事务,反之父事务影响嵌套事务
- Spring的事务隔离有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致
-
用法
- 假设有两个业务方法A和B,方法A在方法B中被调用,需要在事务中保证它们的一致性,如果方法A或方法B中的任何一个方法发生异常,则需要回滚事务
- 使用Spring的事务传播机制,可以在方法A和方法B上使用相同的事务管理器,并通过设置相同的传播行为来保证事务的一致性和完整性
- 具体实现如下:

- 在上述示例中,方法A和方法B都使用了REQUIRED的传播行为,表示如果当前存在事务,则在当前事务中执行;
- 如果当前没有事务,则创建一个新的事务
- 如果在方法A或方法B中出现异常,则整个事务会自动回滚
-
rollbackFor
- rollbackFor是Spring事务中的一个属性,用于指定哪些异常会触发事务回滚
- 在一个事务方法中,如果发生了rollbackFor属性指定的异常或其子类异常,则事务会回滚
- 如果不指定rollbackFor,则默认情况下只有RuntimeException和Error会触发事务回滚
-
场景举例
- 问:一个长的事务方法a,在读写分离的情况下,里面既有读库操作,也有写库操作,再调用个读库方法b,方法b该用什么传播机制呢?
- 这种情况,读方法如果是最后一步,直接not_supported就行了,避免读报错导致数据回滚
- 如果是中间步骤,最好还是要required,因为异常失败需要回滚一下
-
事务接口
- PlatformTransactionManager:(平台)事务管理器
- TransactionDefinition:事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)
- TransactionStatus:事务运行状态
- 所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”
- PlatformTransactionManager接口介绍
- Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现
- Spring事务管理器的接口是:org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了
- PlatformTransactionManager接口中定义了三个方法:

- #getTransaction(TransactionDefinition definition)方法,根据事务定义 TransactionDefinition,获得 TransactionStatus
- 为什么不是创建事务呢?
- 因为如果当前如果已经有事务,则不会进行创建,一般来说会跟当前线程进行绑定
- 如果不存在事务,则进行创建
- #commit(TransactionStatus status)方法,根据 TransactionStatus 情况,提交事务
- 为什么根据 TransactionStatus 情况,进行提交?
- 例如说,带@Transactional 注解的的 A方法,会调用 @Transactional 注解的的 B 方法
- 在 B 方法结束调用后,会执行 PlatformTransactionManager#commit(TransactionStatus status)方法,此处事务是不能、也不会提交的
- 而是在 A 方法结束调用后,执行 PlatformTransactionManager#commit(TransactionStatus status)方法,提交事务
- 使用 Spring 事务通过 PlatformTransactionManager,为不同的数据层持久框架提供统一的API,无需关心到底是原生 JDBC、Spring JDBC、JPA、Hibernate 还是 MyBatis
相关文章:
Spring-事务管理-加强
目录 开启事务 编程式事务 声明式事务 声明式事务的优点 声明式事务的粒度问题 声明式事务用不对容易失效 Spring事务失效可能是哪些原因 Transactional(rollbackFor Exception.class)注解 Spring 事务的实现原理 事务传播机制 介绍 用法 rollbackFor 场景举例 …...
Minecraft个人服务器搭建自己的皮肤站并实现外置登录更换自定义皮肤组件
Minecraft个人服务器搭建自己的皮肤站并实现外置登录更换自定义皮肤组件 大家好,我是艾西有不少小伙伴非常喜欢我的世界Minecraft游戏,今天小编跟大家分享下Minecraft个人服务器怎么设置皮肤站。 Minecraft皮肤站是什么?其实官网就有皮肤站…...
解决ubuntu中没有网络连接的图标
现象:Ubuntu连接网络 在设置中没有显示网络图标 解决方案: 命令为 sudo nmcli networking off sudo nmcli networking on sudo service network-manager restart 重启ubuntu,网络连接完成...
数据结构基本概念-Java常用算法
数据结构基本概念-Java常用算法 1、数据结构基本概念2、数据逻辑结构3、算法时间复杂度 1、数据结构基本概念 数据(Data):数据是信息的载体,其能够被计算机识别、存储和加工处理,是计算机程序加工的“原材料”。数据元…...
流程图设计制作都有哪些好用的工具
流程图是一种直观的图形表示方式,通常用于显示事物的过程、步骤和关系。在现代工作中,设计师经常需要绘制各种流程图来解释工作过程、产品设计等。本文将为您推荐7个流程图软件,以帮助您快速绘制高效的流程图,并提高工作效率。 即…...
2023-10-7
今日感冒了,整个人都不舒服,现在才 8 点,已经不想学习了。嗓子眼感觉不属于我了,痛死了。然后头也晕。 哎,今天又啥也没干 今日学习: 哎,今天就做了 RWCTF2022-Digging-into-kernel-2 这道题…...
【java源码】二甲医院his系统全套源码 云HIS系统源码
基层医院云HIS系统源码 一款满足基层医院各类业务需要的云HIS系统。该系统能帮助基层医院完成日常各类业务,提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一系列常规功能,还能与公卫、PACS等各类外部系统融合&…...
LRU 缓存 -- 哈希链表
相关题目 146. LRU 缓存 要让 put 和 get ⽅法的时间复杂度为 O(1),我们可以总结出 cache 这个数据结构必要的条件: 1、显然 cache 中的元素必须有时序,以区分最近使⽤的和久未使⽤的数据,当容量满了之后要删除最久未使⽤的那个元…...
DWC数字世界大会先导论坛将于10月13日在宁波举办 | 数字技术赋能世界可持续发展
农业经济影响世界数千年,工业经济从欧美发源开始已有数百年,数字经济作为世界未来发展之大势,将成为影响未来数百年的世界命题。在以中国式现代化全面推进中华民族伟大复兴的历史征程中,数字技术、数字经济作为中国式现代化实践最…...
Springboot实现登录功能(token、redis、登录拦截器、全局异常处理)
登录流程: 1、前端调用登录接口,往接口里传入账号,密码 2、根据账号判断是否有这个用户,如果有则继续判断密码是否正确 3、验证成功后,则是根据账号,登录时间生成token(用JWT) 4、将…...
AI工程化—— 如何让AI在企业多快好省的落地?
文章目录 前言内容简介读者对象专家推荐目录赠书活动 前言 作为计算机科学的一个重要领域,机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律,帮助人们解决众多实际问题。随着机器学习技术的发展,越来越多…...
mysqld_multi测试
mysqld_multi测试 mysql版本:5.7.25-log 在OS上分别安装了两套mysql, data目录为/mysql/mysql3306、 /mysql/mysql3307 。 端口分别为3306 、3307 配置文件为: /mysql/mysql3306/my.cnf /mysql/mysql3307/my.cnf 参考文档: htt…...
MDC方式实现简单链路追踪
MDC 方式实现日志链路追踪 拦截器 package com.cdn.log.interceptor;import com.cdn.log.consts.CLogConst; import com.cdn.log.utils.IdUtil; import org.slf4j.MDC; import org.springframework.util.StringUtils; import org.springframework.web.servlet.ModelAndView; im…...
Linux深度学习:除基本命令操作外的实用操作
Linux深度学习:除基本命令操作外的实用操作 软件安装systemctl软连接日期、时区IP地址、主机名网络传输下载和网络请求端口 进程管理主机状态系统资源监控磁盘信息监控网络状态监控 环境变量上传、下载压缩、解压root用户、用户、用户组管理查看、修改权限控制 软件…...
app对接广告变现平台:影响app广告单价的4大因素
在移动应用开发者和媒体公司竞相寻求提高广告变现效率的今天,理解影响APP广告单价的关键因素至关重要。广告单价是广告收入的核心组成部分,它受多种因素的影响,直接关系到媒体的盈利能力。主要因素大概有以下几点:#APP广告变现# …...
【数字化转型】10大数字化转型能力成熟度模型01(IOMM)
一、前言 数字化转型是数据化能力建设的目标和价值,作为一个新兴的课题,目前为止并未出现一个统一的数字化转型成熟度模型。不同的企业和机构,根据自身的发展和认知,推出了自己的企业级或者准行业级标准。这些标准具有很强的参考意…...
2023腾讯云轻量应用服务器和普通服务器有什么区别?
腾讯云轻量服务器和云服务器有什么区别?为什么轻量应用服务器价格便宜?是因为轻量服务器CPU内存性能比云服务器CVM性能差吗?轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境,云服务器CV…...
SSL证书是什么?1分钟get
在当今互联网世界中,保护数据的完整性和隐私性至关重要,由此,在网络数据安全保护领域,作为保护网络传输数据安全的SSL证书越来越频繁出现。那么你知道SSL证书是什么?SSL证书有哪些类型?SSL证书有什么用吗&a…...
3D打印机升级killpper
本来是想整台新机的,但是想想老机器4max也不能就此放弃,看了看视频,改装升级似乎也没有那么难。然后就是换了喷头、皮带、轴承、挤出机、打印平台、加热板等等。做了干燥箱,改装挤出机结构来适配,风扇口也一并搞掉&…...
源码编译dotnetcore的runtime
为了dotnetcore运行时的安可目标,特意在国庆假期研究了怎么编译dotnetcore的runtime。由于我们用的是.net6,最新的是8,所以从github下载的.net6的分支代码进行的编译。查遍了国内外资料,估计微软服务太体贴了,竟然没什…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
