SpringBoot事务处理
一、事务回顾
回顾地址: 深入理解数据库事务(超详细)_数据库事务操作_Maiko Star的博客-CSDN博客
事务: 是一组操作的集合,是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败
事务的操作
- 开启事务(一组操作开始前,开启事务):start transaction / begin
- 提交事务:(这组操作全部成功后,提交事务),commit
- 回滚事务:(中间任何一个操作出现异常,回滚事务),rollback
SpringBoot中的事务是指一组操作数据库的动作集合,事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做。
二、SpringBoot事务的实现方式
(1)声明式事务管理(推荐)
声明式事务管理建立在 AOP 之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行目标方法之后根据执行的情况提交或者回滚事务。声明式事务管理不需要入侵代码,通过 @Transactional 就可以进行事务的操作,推荐使用。
- 在方法上添加
@Transactional注解,表示该方法需要被事务管理。 - 使用
Propagation属性指定事务的传播行为,默认是REQUIRED,即如果当前存在事务,则加入该事务,如果没有事务,则新建一个事务。 - 使用
Isolation属性指定事务的隔离级别,默认是数据库的默认隔离级别。 - 使用
readOnly属性指定事务是否为只读,如果为只读,则在事务中不允许进行写操作,默认为false。 - 使用
rollbackFor属性指定哪些异常触发事务回滚,默认为RuntimeException。
示例代码:
@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public User createUser(User user) {// 业务逻辑return userRepository.save(user);}public void updateUser(User user) {// 业务逻辑userRepository.save(user);}
}
(2)编程式事务管理
编程式事务管理使用 TransactionTemplate或者直接使用底层的 PlatformTransactionManager。对于编程式事务管理,spring 推荐使用 TransactionTemplate。
- 使用
TransactionTemplate手动控制事务的开始和提交/回滚。 - 在
execute方法内部执行需要被事务管理的业务逻辑。
示例代码:
@Service
public class UserService {@Autowiredprivate TransactionTemplate transactionTemplate;@Autowiredprivate UserRepository userRepository;public User createUser(User user) {return transactionTemplate.execute(status -> {try {// 业务逻辑return userRepository.save(user);} catch (Exception e) {status.setRollbackOnly();throw e;}});}public void updateUser(User user) {transactionTemplate.execute(status -> {try {// 业务逻辑userRepository.save(user);} catch (Exception e) {status.setRollbackOnly();throw e;}return null;});}
}
三、@Transactional 注解介绍及使用
3.1 @Transactional 作用范围
@Fransactional 可以用来修饰方法或类:
- 修饰方法时:表示当前的方法开启事务,需要注意只能应用在 public 方法上。
- 修饰类时:表示当前该类下面的所有被 public 修饰的方法都开启事务。
- 默认会回滚运RuntimeException 及其子类

3.2 @Transactional 参数说明
| 参数 | 作用 |
|---|---|
| value | 当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。 |
| transactionManager | 当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。 |
| propagation | 事务的传播行为,默认值为 Propagation.REQUIRED。 |
| isolation | 事务的隔离级别,默认值为 Isolation.DEFAULT。 |
| timeout | 事务的超时时间,默认值为-1(表示没有超时时间)。如果超过该超时时间显示但事务还没有完成,则自动回滚事务。 |
| readOnly | 指定事务是否为只读事务,默认值为 false。为了忽略那些不需要事务的方法,比如读取数据,可以设置为 true。 |
| rollbackFor | 用于指定能够被触发事务回滚的异常类型,可以指定多个异常类型。 |
| rollbackForClassName | 用于指定能够被触发事务回滚的异常类型,可以指定多个异常类型。 |
| noRollbackFor | 抛出异常的类型,不回滚事务,也可以指定多个异常类型。 |
| noRollbackForClassName | 抛出异常的类型,不回滚事务,也可以指定多个异常类型。 |
参数名称功能描述readOnly该属性用于设置当前事务是否为只读模式,设置为 true 表示只读,false 表示可读可写,默认情况下是 false。
例如: @Transactional(readOnly = true)rollbackFor该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。
例如:
指定单一异常类:@Transactional(rollbackFor = Exception.class)
指定多个异常类:@Transactional(rollbackFor ={RuntimeException.class,Exception.class})rollbackForClassName该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。
例如:
指定单一异常类名:@Transactional(rollbackForClassName = "RuntimeException")
指定多个异常类名:@Transactional(rollbackForClassName = {"RuntimeException","Exception"})noRollbackFor该属性用于设置不需要进行回滚的异常类数组。使用方法同 rollbackFornoRollbackForClassName该属性用于设置不需要进行回滚的异常类名称数组。使用方法同 rollbackForClassNamepropagation该属性用于设置事务的传播行为。isolation该属性用于设置事务的隔离级别。timeout该属性用于设置事务的超时秒数,默认值为 -1 表示永不超时。
3.3 @Transactional 出现异常注意事项
1.@Transactional 只能放在 public 修饰的方法上。
2.@Transactional,不加任何参数时,默认会回滚运RuntimeException 及其子类,其它范围之外的异常 Spring 不会帮我们去回滚数据。
3.@Transactional(rollbackFor = Exception.class),如果加上rollbackFor 参数,会回滚所指定的异常类,前提下一定要在catch中抛出相关异常类,否则事务还是失效的。
4.@Transactional 在异常被捕获的情况下,不会进行事务的自动回滚。
默认情况下,Spring 中的事务如果遇到运行时异常,事务是会进行回滚的,但遇到非运行时异常,事务不会自动回滚。可以设置 rollbackFor 来解决非运行时异常不会被回滚的问题。示例代码如下:
@RequestMapping("/test3")
@Transactional
public String test3(@RequestParam String username, @RequestParam String pwd) {// 插⼊数据库int result = userService.addUser(username, pwd);try {// 执⾏了异常代码int i = 10 / 0;} catch (Exception e) {}
以上代码虽然出现了算数异常,但是由于主动捕获了,且没有进行抛出,因此不会进行事物的回滚,数据库中会插入该条数据。
如果要解决出现异常事务不能自动回滚的问题,以下提供两种解决方案:
(1)方案一:对于捕获的异常,事务是不会自动回滚的,因此可以在捕获异常后主动将该异常重新抛出。默认只回滚RunTimeException,故我们这里演示抛出RunTimeException,示例代码如下:
@RequestMapping("/test3")
@Transactional
public String test3(@RequestParam String username, @RequestParam String pwd) {// 插⼊数据库int result = userService.addUser(username, pwd);try {// 执⾏了异常代码int i = 10 / 0;} catch (Exception e) {// 将异常重新抛出throw new RunTimeException();}return "测试完成!";
}
方案二(推荐):手动去回滚事务,可以通过方法 TransactionAspectSupport.currentTransactionStatus() 得到当前的事务,然后设置回滚方法 setRollbackOnly 就可以实现回滚。示例代码如下:
@RequestMapping("/test3")
@Transactional
public String test3(@RequestParam String username, @RequestParam String pwd) {// 插⼊数据库int result = userService.addUser(username, pwd);try {// 执⾏了异常代码int i = 10 / 0;} catch (Exception e) {// 手动回滚
TransactionStatus transactionStatus = TransactionAspectSupport.currentTransactionStatus();transactionStatus.setRollbackOnly();}return "测试完成!";
}
使用了TransactionAspectSupport类来获取当前的事务状态,并通过调用setRollbackOnly()方法手动回滚事务。这是Spring框架中一种手动回滚事务的方式。
3.4 @Transactional 失效的情况排查
问题:方法上添加了 @Transactional 注解,为什么没有进行回滚?
排查一:是否使用了 try catch 进行了异常捕获,并且捕获之后,没有通过 throw new RuntimeException(); 进行异常抛出。因为对于 spring aop 异常捕获原理,被拦截的方法需要显示的抛出异常,并不能进行任何处理,这样 aop 代理才能捕获到方法的异常,才能进行事务的回滚操作;默认清空下,aop 只捕获 RuntimeException 的异常,但是可以通过配置来捕获特定的异常并回滚。
排查二:是否使用了 try catch 进行了异常信息捕获,如果是可以在 catch 语句中添加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(),手动回滚事务
排查三:排查是不是产生了自调用的问题。在 spring 的 aop 代理下,只有目标方法被外部调用,目标方法才由 spring 生成的代理对象来管理;若统一类中的其他没有用 @Transactional 注解进行修饰的方法内部调用了 用 @Transactional 注解进行修饰的方法,有 @Transactional 注解的方法的事务将会被忽略,不发生回滚。(周氏概括:即没有使用@Transactional 注解修饰的方法调用了用 @Transactional 注解进行修饰的方法,将会导致事务失效)
备注:如果确实需要这样操作,只需要把 @Transactional 注解加在当前的类名上就可以了 或者使用 AspectJ 取代 spring aop 进行代理。
排查四:@Transactional 注解只被应用到 public 修饰的方法上;如果在 protected、private等修饰的方法上,@Transactional 注解不会报错,但是这个注解的将不会生效。
排查五:@Transactional 注解不会对当前修饰的方法的处理异常的子方法生效。比如:我们在方法 A 中声明了 @Transactional 注解,但是 A 方法的内部调用的 方法 B 和 方法 C,其中方法 B 进行了 数据库的操作,但是该部分的异常被方法 B 进行了处理并且没有进行 抛出,这样的话事务是不会生效的。如果想要事务生效,需要将子方法的事务控制交给调用的方法,在子方法中使用 @Transactional注解并通过 rollbackFor 指定定回滚的异常 或者直接将异常抛出。(周氏概括:使用@Transactional 注解修饰的A方法 调用了 没有用@Transactional 注解修饰的B方法,但是B方法使用try catch处理了异常,这将导致事务失效。使用@Transactional 注解修饰的A方法 调用了 没有用@Transactional 注解修饰的B方法,但是B方法将异常向上抛出或使用@Transactional注解并通过 rollbackFor 指定定回滚的异常,事务不会失效。)
备注:在使用事务的时候,最好把子方法的异常进行抛出,交给调用的方法进行处理。
四、SpringBoot事务传播机制(了解)
4.1 事务传播机制的定义
Spring 事务传播机制定义了多个包含了事务的方法在相互调用时,事务是如何在这些方法之间进行传递的。
4.2 事务传播机制的作用
- 事务隔离级别是保证多个并发事务执行的可控性,而事务传播机制是保证一个事务在多个调用方法之间的可控性。
- 事务隔离级别是解决多个事务同时调用数据库的问题,而事务传播机制是解决一个事务在多个节点中传递的问题。
4.3 Spring 事务传播机制有7种
- Propagation.REQUIRED: 默认的事务传播机制,它表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- Propagation.SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- Propagation.MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- Propagation.REQUIRES_NEW: 表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,该传播机制修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
- Propagation.NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- Propagation.NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
- Propagation.NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 Propagation.REQUIRED。
嵌套事务和加入事务的区别:
- 嵌套事务:回事有问题的事务,但主事务不受影响。
- 加入事务:如果任意一个方法出现异常,那么整个事务会回滚。
相关文章:
SpringBoot事务处理
一、事务回顾 回顾地址: 深入理解数据库事务(超详细)_数据库事务操作_Maiko Star的博客-CSDN博客 事务: 是一组操作的集合,是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败 事…...
网络安全—自学
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟…...
首页以卡片形式来展示区块链列表数据(Web3项目一实战之五)
我们已然在 Web3 分布式存储 IPFS(Web3项目一实战之四) 介绍了什么是IPFS,以及在本地电脑如何安装它。虽然在上一篇讲解了该怎么安装IPFS,也做了相应的配置,但在本地开发阶段,前端总是无法避免跨域这个远程请求api的”家常便饭的通病“。 很显然,对于出现跨域这类常见问…...
opencv使用pyinstaller打包错误:‘can‘t find starting number (in the name of file)
使用Python语言和opencv模块在pycharm中编辑的代码运行没问题,但是在使用pyinstaller打包后出现错误can‘t find starting number (in the name of file) [ERROR:0] global C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-q3d_8t8e\opencv\modules\videoi…...
4.一维数组——用数组处理求Fibonacci数列前20项
文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 四、结果显示 前言 本系列为一维数组编程题,点滴成长,一起逆袭。 一、题目描述 用数组处理求Fibonacci数列前20项 二、题目分析 前两项:f[20]{1,1} 后18项:for(…...
讯飞星火知识库文档问答Web API的使用(二)
上一篇提到过星火spark大模型,现在有更新到3.0: 给ChuanhuChatGPT 配上讯飞星火spark大模型V2.0(一) 同时又看到有知识库问答的web api,于是就测试了一下。 下一篇是在ChuanhuChatGPT 中单独写一个基于星火知识库的内容…...
第十三章 深度解读预训练与微调迁移,模型冻结与解冻(工具)
一个完整的代码 pythonCopy codeimport torch import torchvision import torchvision.transforms as transforms import torch.nn as nn import torch.optim as optim # 设置设备(CPU或GPU) device torch.device("cuda" if torch.cuda.is_a…...
tinyViT论文笔记
论文:https://arxiv.org/abs/2207.10666 GitHub:https://github.com/microsoft/Cream/tree/main/TinyViT 摘要 在计算机视觉任务中,视觉ViT由于其优秀的模型能力已经引起了极大关注。但是,由于大多数ViT模型的参数量巨大&#x…...
解决ssh -T git@github.com报错connection closed问题
解决ssh -T gitgithub.com报错connection closed问题 问题解决 问题 $ ssh -T gitgithub.com kex_exchange_identification: Connection closed by remote host Connection closed by 20.205.243.166 port 22解决 参考链接 $ ssh -T -p 443 gitssh.github.com...
新手如何购买保险,保险投资基础入门
一、教程描述 本套保险教程,大小2.63G,共有11个文件。 二、教程目录 第01课 保险到底有什么用.mp4 第02课 已有社保还需要商业保险吗.mp4 第03课 你必须要懂的保险基础知识.mp4 第04课 关于重疾你必须要知道的几件事情.mp4 第05课 家庭重疾险如何…...
基于springboot网上超市管理系统
基于springboot网上超市管理系统 摘要 随着互联网的快速发展,电子商务行业迎来了蓬勃的发展,网上超市作为电子商务的一种形式,为消费者提供了便利的购物体验。本文基于Spring Boot框架,设计和实现了一个网上超市管理系统ÿ…...
FlagEmbedding目前最好的sentence编码工具
FlagEmbedding专注于检索增强llm领域,目前包括以下项目: Fine-tuning of LM : LM-Cocktail Dense Retrieval: LLM Embedder, BGE Embedding, C-MTEB Reranker Model: BGE Reranker 更新 11/23/2023: Release LM-Cocktail, 一种通过模型融合在微调时保持原有模型通用…...
rabbitMQ发布确认-交换机不存在或者无法抵达队列的缓存处理
rabbitMQ在发送消息时,会出现交换机不存在(交换机名字写错等消息),这种情况如何会退给生产者重新处理?【交换机层】 生产者发送消息时,消息未送达到指定的队列,如何消息回退? 核心&…...
STM32 MAP文件
文章目录 1 生成Map2 map中概念3 文件分析流程3.1 Section Cross References3.2 Removing Unused input sections from the image(移除未使用的段)3.3 Image Symbol Table 映像符号表3.4 Memory Map of the image(映像的内存分布)…...
云原生Kubernetes系列 | Kubernetes静态Pod的使用
云原生Kubernetes系列 | Kubernetes静态Pod的使用 静态pod不建议在master上操作,因为master上跑的是集群核心静态pod,如果配置失败,会导致集群故障。建议在knode1或knode2上去做。 kubernetes master节点上的核心组件pod其实都是静态pod: [root@k8s-master ~]# ls /etc/ku…...
二次创作Z01语言
目录 一,字符集 二,编译分词 三,token含义 四,Z01翻译成C 五,执行翻译后的代码 六,打印Hello World! 一,字符集 假设有门语言叫Z01语言,代码中只有0和1这两种字符。 二&#…...
【蓝桥杯国赛真题28】Scratch行驶的汽车 少儿编程图形化编程 中小学生第十四届蓝桥杯scratch国赛真题讲解
目录 scratch行驶的汽车 一、题目要求 编程实现 二、案例分析 1、角色分析...
LeetCode Hot100 236.二叉树的最近公共祖先
题目: 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节…...
ERROR: Could not find a version that satisfies the requirement torch
在windows 上安装pip install torch torchvision torchaudio 报错: ERROR: Could not find a version that satisfies the requirement torch (from versions: none) ERROR: No matching distribution found for torch 解决办法: 将python版本降到3.11…...
2009年iMac装64位windows7及win10
2009年iMac装64位windows7及win10 Boot Camp没有“创建 Windows7 或更高版本的安装磁盘”选项 安装完Mac OS系统后,要制作Windows7安装U盘时才发现,Boot Camp没有“创建 Windows7 或更高版本的安装磁盘”选项,搜索到文章:修改Boo…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
