Spring中的事务和事务的传播机制
事务是一组操作的集合,不可以被分割。事务会把所有的操作作为一个整体,这组操作要么全部成功,要么全部失败。
事务有三种操作:
- 开启事务;
- 提交事务;
- 回滚事务。
如果代码的执行逻辑是这样:
开启事务业务A回滚事务
此时A当中的所有操作都不会生效
开启事务业务A提交事务
开启事务后只有这种情况下A中的逻辑才会生效
Spring中事务的实现有两种
编程式(手动操作事务)
Spring Boot对于事务操作内置了两个类,我们在使用时可以选择直接注入:
- DataSourceTransactionManager:事务管理器,里面包含了事务的操作和获取;
- TransactionDefinition:事务的属性。在获取事务时需要充当参数。
提交事务
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {//获取事务管理器@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;//获取事务属性@Autowiredprivate TransactionDefinition definition;@Autowiredprivate UserMapper userMapper;@RequestMapping("/fun1")public void fun1() {//获取并开启事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(definition);//业务操作//向数据库中插入一条数据userMapper.userInsert("zhangsan","man");//打印日志log.info("数据插入完成");//提交事务dataSourceTransactionManager.commit(transaction);}
}
@Mapper
public interface UserMapper {@Insert("insert into userinfo(username,gender) values (#{userName},#{gender});")void userInsert(String userName, String gender);
}
这是数据库的初始状态

代码执行后数据成功插入

回滚事务
@RequestMapping("/fun1")
public void fun1() {//获取并开启事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(definition);//业务操作userMapper.userInsert("zhangsan","man");log.info("数据插入完成");//提交事务
// dataSourceTransactionManager.commit(transaction);//回滚事务dataSourceTransactionManager.rollback(transaction);
}
当代码执行成功后,数据库中的数据并没有变多。
注解式(利用注解自动实现事务)
使用注解实现事务是非常简单的只需要给需要添加事务的方法加上@Transactional注解。添加该注解后程序会自动的在方法开始前开启事务,在方法结束后提交事务;如果在方法执行中发生了没有处理的异常会自动进行回滚事务。
@Transactional既可以修饰方法也可以修饰类:
- 修饰方法时该方法必须是被public修饰的方法,否则既不会生效也不会报错;
- 当修饰类时,会对该类中的所有被public修饰的方法生效。
当方法正常执行完毕后会自动提交事务 :
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("lisi","man");log.info("数据插入完成");}
}

当方法执行过程中发生异常时自动回滚事务 (该注解默认只回滚运行时异常<RuntimeException
>和错误<error>):
发生运行时异常,事务回滚:
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("lisi111","man");log.info("数据插入完成");//发生运行时异常,事务回滚throw new RuntimeException();}
}

编译时异常不会回滚:
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional@RequestMapping("/fun2")public void fun2() throws IOException {userMapper.userInsert("lisi111","man");log.info("数据插入完成");//发生编译时异常,事务不会回滚throw new IOException();}
}


此时尽管程序已经报错了,可数据还是正常插入了。如何解决这个问题呢?
rollbackFor
可以通过配置 @Transactional 注解当中的 rollbackFor 属性,通过 rollbackFor 这个属性来指定出现何种异常类型时事务进行回滚。
这个属性的类型是数组需要注意
Class<? extends Throwable>[] rollbackFor() default {};
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;//此时会回滚所有的Exception类型的异常@Transactional(rollbackFor = {Exception.class})@RequestMapping("/fun2")public void fun2() throws IOException {userMapper.userInsert("lisi222","man");log.info("数据插入完成");//此时发生编译时异常,事务回滚throw new IOException();}
}

此时error类型的错误依然会进行回滚。
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional(rollbackFor = {Exception.class})@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("lisi222","man");log.info("数据插入完成");//会发生栈溢出错误,仍然会回滚while(true) {fun2();}}
}
手动回滚事务
使用 TransactionAspectSupport.currentTransactionStatus() 得到当前的事务,并使用setRollbackOnly使事务进行回滚
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional(rollbackFor = {Exception.class})@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("66666","man");log.info("数据插入完成");//手动设置回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}

事务隔离级别
SQL中的事务隔离级别:
- 读未提交(READ UNCOMMITTED):读未提交,也叫未提交读。该隔离级别的事务可以看到其他事务中未提交的数据(未提交的数据可能会发生回滚,但是该隔离级别却可以读到,这个问题称之为脏读);
- 读已提交(READ COMMITTED):也叫提交读,该隔离级别的事务能读取到已经提交事务的数据。(该隔离级别不会有脏读的问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同SQL查询可能会得到不同的结果,这种现象叫做不可重复读);
- 可重复读(REPEATABLE READ):事务不会读到其他事务对已有数据的修改,即使其他事务已提交。可重复读,是MySQL的默认事务隔离级别。(虽然可以确保同一事务多次查询的结果一致,但是其他事务新插入的数据,是可以感知到A事务正在执行时,另⼀个事务成功的插入了某条数据,而此时A事务如果再查寻数据库就会导致两次查找到的“结果集”不同<数据变多了>,这个现象叫幻读。);
- 串行化(SERIALIZABLE):序列化,事务最高隔离级别。它会强制事务排序,使之不会发生冲突,从而解决了脏读,不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。
Spring中的事务隔离级别:
- Isolation.DEFAULT :以连接的数据库的事务隔离级别为主;
- Isolation.READ_UNCOMMITTED :读未提交;
- Isolation.READ_COMMITTED :读已提交;
- Isolation.REPEATABLE_READ :可重复读;
- Isolation.SERIALIZABLE :串行化;
事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置
@Transactional(isolation = Isolation.DEFAULT)
@RequestMapping("/fun2")
public void fun2() {}

事务的传播机制
如果A方法中调用B方法那么B方法是使用A方法的事务还是自己的事务,事务的传播机制就是为了解决该问题。
@Transactional 注解支持事务传播机制的设置,通过 propagation 属性来设置。
Spring 事务传播机制有 7 种(在A方法中调用B(七种传播机制都设置在该方法上)方法):
- Propagation.REQUIRED:默认的事务传播级别。如果A存在事务,则B加入该事务。如果A没有事务,则B创建一个新的事务;
- Propagation.SUPPORTS:如果A存在事务,则B加入该事务。如果A没有事务,则B以非事务的方式继续运行;
- Propagation.MANDATORY:强制性。如果A存在事务,则B加入该事务。如果A没有事务,B抛出异常;
- Propagation.REQUIRES_NEW:创建一个新的事务。不管A是否开启事务,B都会重新创建一个事务,且创建的事务相互独立,互不干扰;
- Propagation.NOT_SUPPORTED:以非事务方式运行。无论A是否存在事务,B都以非事务运行;
- Propagation.NEVER:以非事务方式运行。如果A存在事务,则抛出异常;
- Propagation.NESTED :如果A存在事务,则B创建一个事务作为当前事务的嵌套事务来运行。如果A没有事务,B创建一个事务。
@Transactional(propagation = Propagation.MANDATORY)
@RequestMapping("/fun2")
public void fun2() {}

相关文章:
Spring中的事务和事务的传播机制
事务是一组操作的集合,不可以被分割。事务会把所有的操作作为一个整体,这组操作要么全部成功,要么全部失败。 事务有三种操作: 开启事务;提交事务;回滚事务。 如果代码的执行逻辑是这样: 开…...
前端【技术类】资源学习网站整理(那些年的小网站)
学习网站整理 值得分享的视频博主:学习网站链接 百度首页的资源收藏里的截图(排列顺序没有任何意义,随性而已~),可根据我标注的关键词百度搜索到这些网站呀,本篇末尾会一一列出来,供大家学习呀 …...
MySQL——存储引擎
存储引擎 InnoDB 是 MySQL 默认的存储引擎,只有在需要它不支持的特性时,才会考虑其他存储引擎 实现了 4 个标准的隔离级别,默认级别可重复度。在可重复度隔离级别下,通过 MVCC 间隙锁防止幻读 主索引是聚簇索引 内部做了很多…...
YoloV8改进策略:Block改进|MogaNet——高效的多阶门控聚合网络
文章目录 摘要论文:《MogaNet——高效的多阶门控聚合网络》1、简介2、相关工作2.1、视觉Transformers2.2、ViT时代的卷积网络3、从多阶博弈论交互的角度看表示瓶颈4、方法论4.1、MogaNet概述4.2、多阶门控聚合4.3、通过通道聚合进行多阶特征重新分配4.4、实现细节5、实验5.1、…...
关于vue3使用prop传动态参数时父子数据不同步更新问题
子: <template><div><h3>子组件</h3><input :value"modelValue" input"$emit(update:modelValue, $event.target.value)"></div> </template><script setup> import { defineProps, defineEmits } from …...
招投标系统:从线下招标到高效数字化
随着科技的不断进步,越来越多的企业开始意识到传统的线下招标方式存在的种种限制,并积极转向电子招投标系统。这一趋势的兴起不仅是数字化转型的必然选择,更是企业提高效率、降低成本的有效途径。 招投标系统的定义与作用 招投标系统是一种…...
day08_分类品牌管理商品规格管理商品管理
文章目录 1 分类品牌管理1.1 菜单添加1.2 表结构介绍1.3 页面制作1.4 品牌列表加载1.4.1 后端接口BrandControllerBrandServiceBrandMapperBrandMapper.xml 1.4.2 前端对接brand.jscategoryBrand.vue 1.5 分类数据加载1.6 列表查询1.6.1 需求说明1.6.2 后端接口需求分析Categor…...
手写分布式配置中心(二)实现分布式配置中心的简单版本
这一篇文章比较简单,就是一个增删改查的服务端和一个获取配置的客户端,旨在搭建一个简单的配置中心架构,代码在 https://gitee.com/summer-cat001/config-center 服务端 服务端选择用springboot 2.7.14搭建,设计了4个接口/confi…...
跨境知识分享:什么是动态IP?和静态IP有什么区别?
对于我们跨境人来说,清楚地了解IP地址、代理IP等这些基础知识,并学会正确地使用IP地址对于保障店铺的安全性和稳定性至关重要,尤其是理解动态IP和静态IP之间的区别,以及如何利用这些知识来防止账号关联,对于每个电商卖…...
liunx安装jdk、redis、nginx
jdk安装 下载jdk,解压。 sudo tar -zxvf /usr/local/jdk-8u321-linux-x64.tar.gz -C /usr/local/ 在/etc/profile文件中的,我们只需要编辑一下,在文件的最后加上java变量的有关配置(其他内容不要动)。 export JAVA_HOME/usr/l…...
【C++】STL学习之旅——初识STL,认识string类
string类 1 STL 简介2 STL怎么学习3 STL缺陷4 string4.1 初识 string4.2 初步使用构造函数成员函数 5 小试牛刀Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!! 1 STL 简介 …...
Java学习笔记002——类的修饰符
在Java语言中,类的访问修饰符决定了其它类能够访问该类的方式。类有如下4种访问修饰符,在创建类时用于类的声明: 1、public: 当一个类被声明为public时,它可以从任何其他类中被访问,无论这些类位于哪个包中。通常&am…...
华为交换机常见命令总结
文章目录 查看MAC地址清除MAC地址修改MAC地址的老化时间查询STP信息查询接口与vlan的信息 查看MAC地址 查看所有MAC地址表项 display mac-address 查看静态MAC地址表项 display mac-address static //会把动态的过滤掉 查看动态MAC地址表项 display mac-address dynamic //会…...
Android 签名机制
V1是内部文件单个签 但是增加apk文件目录下面随意增加文件并不会有影响,它只关心meta-info文件 mf汇总清单的各个文件sha256 V2 整个APK文件,按文件进行hash 那么便不能随便在这里面增加文件了,增加了签名分块(不然签名信息存哪里)这里涉及一个文件概念 …...
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Scroll容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Scroll容器组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Scroll容器组件 可滚动的容器组件,当子组件的布局尺寸超过父组件…...
FreeRTOS操作系统学习——FreeRTOS工程创建
FreeROTS工程创建 详细步骤 如无特殊情况,大部人都要配置为外部高速时钟 另外,本实验使用了FreeRTOS,FreeRTOS的时基使用的是Systick,而 STM32CubeMX中默认的HAL库时基也是Systick,为了避免可能的冲突,最…...
6. 使用 Spring Boot进行开发(Developing with Spring Boot)
6. 使用 Spring Boot进行开发(Developing with Spring Boot) 本节详细介绍了如何使用Spring Boot。它涵盖考虑构建系统、自动配置以及如何运行应用程序等主题。我们还介绍一些 Spring Boot 最新做法。虽然 Spring Boot 没有什么特别之处(它只…...
IP地址工具,判断IP是否在指定范围内(支持ipv6)
常用方法,判断一个ip是否在指定的ip范围内,范围可能包括起始ip范围或者掩码形式,无其它依赖, package com.yk.ip;import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import jav…...
Redis 之六:Redis 的哨兵模式(Sentinel)
Redis 哨兵(Sentinel)模式是一种高可用性解决方案,用于监控和自动故障转移的集群系统。 在 Redis Sentinel 架构中,哨兵是一组运行在特殊模式下的 Redis 进程,它们可以监控一个或多个主从复制结构中的 Redis 主服务器以…...
总线要点笔记
1. AXI/AHB/APB差异 AMBA (Advanced Microcontroller Bus Architecture) 高级处理器总线架构 AHB (Advanced High-performance Bus) 高级高性能总线 ASB (Advanced System Bus) 高级系统总线 APB (Advanced Peripheral Bus) 高级外围总线 AXI (Advanced eXtensible Interface) …...
突破语言壁垒:PotPlayer字幕实时翻译插件让跨语言视频观看效率提升300%
突破语言壁垒:PotPlayer字幕实时翻译插件让跨语言视频观看效率提升300% 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu 你是…...
5 鸿蒙应用权限配置快速落地实操 | 鸿蒙开发筑基实战
鸿蒙应用权限配置快速落地实操 | 鸿蒙开发筑基实战 作者:杨建宾(华夏之光永存) 摘要 本文面向鸿蒙开发新手与普通工程师,详细讲解鸿蒙应用权限配置的完整实操流程,包含权限分类、配置文件声明、运行时申请、权限校验等…...
基于Cortex-M3和步进电机的数字钟控制及其语音播报系统设计
一、系统概述 系统以Cortex-M3内核单片机(如STM32F103C8T6)为核心,融合步进电机精密驱动、实时时钟(RTC)、语音合成播报三大功能,实现“数字钟精准显示机械指针动态指示定时语音报时”的一体化设计。系统通…...
Scikit-learn的随机SVD真的能“超快”降维吗?先看清代价
先说结论随机SVD确实能大幅提升PCA速度,尤其在样本量大的场景,但代价是可控的精度损失和随机性引入这种优化更适合离线或准实时处理,在严格实时边缘系统中仍可能成为瓶颈,需要结合硬件加速选择随机SVD前,必须明确业务对…...
Gemma-3-12b-it Streamlit应用实战:顶部像素控制面板CSS3定制详解
Gemma-3-12b-it Streamlit应用实战:顶部像素控制面板CSS3定制详解 1. 引言:从传统侧边栏到像素控制面板 如果你用过Streamlit,肯定对那个默认的侧边栏不陌生。它很方便,但有时候也挺碍事——特别是当你想要一个全屏、沉浸式的对…...
Vue2项目里用Cesium加载天地图标注,保姆级避坑指南(含Token申请)
Vue2项目集成Cesium与天地图标注的工程化实践指南 当WebGIS需求遇上Vue技术栈,如何在老项目中优雅地引入三维地图能力?本文将以工程化视角,系统讲解Vue2项目中集成Cesium加载天地图标注的完整技术路径。不同于基础教程,我们将重点…...
AD09 PCB设计核心技巧与实战经验
1. PCB设计基础与AD09平台概述作为一名从业超过十年的硬件工程师,我使用过从Protel 99到Altium Designer 21的各种版本,其中AD09(Altium Designer 2009)因其稳定性和适中的硬件要求,至今仍是许多工程师的首选工具。PCB…...
生产环境Python 3.14 JIT崩溃率突增400%?,资深SRE团队紧急封存的8个未公开__PyJIT_TraceConfig参数调优组合
第一章:Python 3.14 JIT 编译器性能调优生产环境部署全景图Python 3.14 引入的原生 JIT 编译器(代号 “PyJIT”)标志着 CPython 运行时架构的重大演进。它不再依赖外部工具链(如 Cython 或 Numba),而是以内…...
OpenClaw技能开发入门:为千问3.5-9B编写自定义文件处理器
OpenClaw技能开发入门:为千问3.5-9B编写自定义文件处理器 1. 为什么需要自定义文件处理器 上周我在整理项目文档时,发现一个重复性痛点:每次收到同事发来的Markdown文件,都需要手动执行"格式校验→重命名→按日期归档→生成…...
OpenClaw隐私保护方案:Qwen3-14B本地处理敏感数据
OpenClaw隐私保护方案:Qwen3-14B本地处理敏感数据 1. 为什么需要本地化隐私保护方案 去年我在处理一批医疗研究数据时,曾因使用某云端AI服务导致文件误传至公共存储桶。虽然及时删除了数据,但这次经历让我意识到:当涉及法律文书…...

