Spring事务管理详解
一、什么是事务管理
事务是一个最小的不可再分的工作单元。 一个事务对应一套完整的业务操作。事务管理是指这些操作要么全部成功执行,要么全部回滚,从而保证数据的一致性和完整性。比如银行转账,需要保证转出和转入是一个原子操作。Spring提供了声明式
和编程式
两种事务管理方式。
二、Spring编程式事务管理
Spring框架提供了专门用于事务管理的API。要使用Spring实现事务管理需要引入spring-tx依赖
首先在pom.xml文件中引入spring-tx
依赖
<!--spring-tx依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.1.8</version>
</dependency>
其中有三个核心接口
PlatformTransactionManager.class
TransactionDefinitionn.class
TransactionStatus.class
PlatformTransactionManager接口
PlatformTransactionManager
接口是 Spring 提供的平台事务管理器,主要用于管理事务。该接口中提供了三个事务操作的方法。
- TransactionStatus getTransaction(TransactionDefinition definition);
用于获取事务以及状态信息 - void commit(TransactionStatus status);
用于提交事务 - void rollback(TransactionStatus status);
用于回滚事务
PlatformTransactionManager
接口只是代表事务管理的接口,并不知道底层是如何管理事务的,具体如何管理事务则由它的实现类来完成。该接口常见的几个实现类如下:
TransactionDefinition接口
TransactionDefinition
接口是事务定义(描述)的对象,该对象中定义了事务基本属性,并提供了获取事务基本属性的方法,具体如下:
- String getName( ); ---------- 获取事务对象名称
- int getIsolationLevel( ); ---------- 获取事务的隔离级别
- int getPropagationBehavior( ); ---------- 获取事务的传播行为
- int getTimeout( ); ---------- 获取事务的超时时间
- boolean isReadOnly( ); ---------- 获取事务是否只读
事务的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。Spring定义了七种传播行为。
事务的隔离级别
定义了一个事务可能受其他并发事务的影响程度。多个事务并发运行,经常会操作相同的数据来完成各自的任务,可能会出现脏读,不可重复读和幻读的问题。隔离级别有四种。
- 脏读:一个事务读取到了另一个事务未提交的数据
- 不可重复读:同一个事务内多次读取同一数据,但前后两次读取的结果不一致。由其他事务的更新操作造成。
- 幻读:同一个事务内多次查询记录数量,但前后两次查询的结果不一致。由其他事务的插入或删除操作造成。
是否只读
如果一个方法内都是对数据库的select操作
,那么可以设置方法事务为只读,数据库也会对该事务进行特定的优化。只读事务内不能有insert、update、delete的操作。
事务超时
事务可能涉及对后端数据库的锁定,所以长时间的事务运行会不必要的占用数据库资源,设置事务超时时间可以及时释放资源
。
默认实现类DefaultTransactionDefinition
DefaultTransactionDefinition
是 Spring 提供的 TransactionDefinition
接口的默认实现类
@SuppressWarnings("serial")
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {private int propagationBehavior = PROPAGATION_REQUIRED; // 必须使用事务private int isolationLevel = ISOLATION_DEFAULT; //数据库默认隔离级别(可重复读)private int timeout = TIMEOUT_DEFAULT; // 永不超时private boolean readOnly = false; // 不是只读// 其他省略
}
TransactionStatus接口
TransactionStatus
接口是事务的状态,它描述了某一时间点上事务的状态信息。该接口中包含6个方法,具体如下:
- void flush(); ---------- 刷新事务
- boolean hasSavepoint(); ---------- 获取是否存在保存点
- boolean isCompleted(); ---------- 获取事务是否完成
- boolean isNewTransaction(); ---------- 获取是否为新事务
- boolean isRollbackOnly(); ---------- 获取事务是否回滚
- void setRollbackOnly(); ---------- 设置事务回滚
1.在配置文件中配置事务管理器组件
spring-mybatis.xml
<!-- 配置事务管理器 --><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean>
2.在业务逻辑组件方法中使用事务管理器组件实现事务管理功能
// 以添加学生信息为例,需要同时往学生表和学生证表插入数据
@Service
public class StudentService {@Autowiredprivate StudentMapper studentMapper;@Autowiredprivate StudentCardMapper studentCardMapper;@Autowiredprivate PlatformTransactionManager transactionManager;public void addStudent(StudentParam param) {// 1.定义事务属性DefaultTransactionDefinition def = new DefaultTransactionDefinition();// 可以设置事务的隔离级别、传播行为等def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 2.获取事务状态TransactionStatus status = transactionManager.getTransaction(def);try {// 3.执行业务逻辑Student student = BeanUtil.copyProperties(param, Student.class);studentMapper.insertStudent(student);StudentCard card = BeanUtil.copyProperties(param, StudentCard.class);card.setStuId(student.getStuId());studentCardMapper.insertStudentCard(card);// 4.提交事务transactionManager.commit(status);} catch (Exception e) {// 5.异常回滚transactionManager.rollback(status);throw new RuntimeException("添加学生信息失败", e);}}
}
三、Spring声明式事务管理
Spring声明式事务管理
最大的优点在于开发者无需通过编程的方式
来管理事务,只需在配置文件中进行相关的事务规则声明,就可以将事务应用到业务逻辑中。在实际开发中,通常都推荐使用声明式事务管理。
Spring声明式事务管理
通过AOP技术
实现的事务管理,主要思想是将事务作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”植入到业务目标类方法中。
Spring的声明式事务管理可以通过两种方式来实现
- 基于XML方式
- 基于注解方式
首先在pom.xml文件中引入AOP切面依赖
<!-- AOP --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.1.8</version></dependency>
XML配置方式
1. 在Spring配置文件中配置事务管理器
spring-mybatis.xml
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean>
2.使用<tx:advice>
标签配置事务规则
spring-mybatis.xml
<!-- 配置事务通知 -->
<!-- id表示唯一标识 transaction-manager表示关联的事务管理器-->
<tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><!-- 定义哪些方法需要进行事务处理,*表示任意字符,比如find*表示以find开头的方法 --><!-- 查询方法:只读事务 --><tx:method name="get*" read-only="true"/><tx:method name="find*" read-only="true"/><tx:method name="select*" read-only="true"/><!-- 增删改方法:读写事务 --><tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/><tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/><tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/><tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED"/></tx:attributes>
</tx:advice>
attributes(属性)
name
:指定对哪些方法起作用propagation
:指定事务的传播行为isolation
:指定事务的隔离级别read-only
:指定事务是否只读timeout
: 指定事务超时的时间rollback-for
:指定异常回滚no-rollback-for
:指定异常不回滚
3. 使用<aop:config>
配置事务切面,通过<aop:pointcut>
配置切点,通过<aop:advisor>
标签配置切点执行的事务规则
spring-mybatis.xml
<!-- 配置事务切面 -->
<!-- 定义切面 -->
<aop:config><!-- 定义切点 --><aop:pointcut id="txPointcut" expression="execution(* com.cg.service.*.*(..))"/><!-- 在指定的切点上应用事务规则 --><!-- advice-ref关联事务规则 pointcut-ref关联切点 --><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
注解方式
基于注解方式实现是通过使用@Transactional
注解来实现方法的事务管理功能
1. 在Spring配置文件中配置事务管理器
spring-mybatis.xml
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean>
2. 在Spring容器中注册事务注解驱动
<!--注册事务注解驱动--><tx:annotation-driven transaction-manager="txManager"/>
3.在需要事务管理的类或方法上使用@Transactional
注解
使用@Transactional注解时,可以通过参数配置具体事务属性
四、事务传播行为详解
通过实际案例理解事务传播行为:
REQUIRED(默认)
如果当前没有事务,就创建一个新事务;如果已经存在一个事务,就加入到这个事务中。
@Service
public class AService {@Autowired private BService bService;@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// methodA开启事务1insert("A");// methodB加入事务1bService.methodB(); // 如果这里抛异常,整个事务都会回滚}
}@Service
public class BService {@Transactional(propagation = Propagation.REQUIRED)public void methodB() {// 加入methodA的事务1insert("B");throw new RuntimeException(); // 异常导致整个事务1回滚}
}
REQUIRES_NEW
总是会开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
@Service
public class AService {@Autowiredprivate BService bService;@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// methodA开启事务1insert("A"); // 这条数据会插入成功try {// methodB开启新事务2,事务1被挂起bService.methodB();} catch (Exception e) {// methodB事务2回滚,事务1不受影响}}
}@Service
public class BService {@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {insert("B1"); // 这条数据会回滚int i = 1/0; // 抛出异常insert("B2"); // 不会执行}
}
NESTED
如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新事务。
@Service
public class AService {@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// 外部事务insert("A"); // 这条数据会保存try {// 内部嵌套事务methodB();} catch (Exception e) {// 内部事务回滚,外部事务可以正常提交}}@Transactional(propagation = Propagation.NESTED)public void methodB() {insert("B"); // 这条数据会回滚throw new RuntimeException();}
}
SUPPORTS
如果当前有事务就加入,没有就以非事务方式执行。
@Service
public class AService { @Transactional(propagation = Propagation.REQUIRED)public void methodA() {// 有事务methodB(); // methodB会加入当前事务}public void methodC() {// 无事务调用methodB(); // methodB以非事务方式执行}
}@Service
public class BService {@Transactional(propagation = Propagation.SUPPORTS)public void methodB() {// 有事务就用事务,没有就不用insert("B");}
}
NOT_SUPPORTED
总是以非事务方式执行,如果当前有事务则挂起。
@Service
publicclass AService {@Transactional(propagation = Propagation.REQUIRED)public void methodA() {insert("A"); // 在事务中执行methodB(); // 挂起当前事务,以非事务方式执行}@Transactional(propagation = Propagation.NOT_SUPPORTED)public void methodB() {// 总是以非事务方式执行insert("B"); // 即使外部有事务也以非事务方式执行}
}
MANDATORY
必须在一个已有事务中执行,否则抛异常。
@Service
public class AService {@Transactional(propagation = Propagation.REQUIRED)public void methodA() {methodB(); // 正常执行,因为当前有事务}public void methodC() {methodB(); // 抛出异常,因为没有事务}
}@Service
public class BService {@Transactional(propagation = Propagation.MANDATORY)public void methodB() {// 必须在一个已有事务中执行insert("B");}
}
NEVER
总是以非事务方式执行,如果当前有事务就抛异常
@Service
public class Aervice {@Transactional(propagation = Propagation.REQUIRED)public void methodA() {methodB(); // 抛出异常,因为当前有事务}public void methodC() {methodB(); // 正常执行,因为没有事务}@Service
public class BService {@Transactional(propagation = Propagation.NEVER)public void methodB() {// 必须在非事务环境下执行insert("B");}
}
相关文章:

Spring事务管理详解
一、什么是事务管理 事务是一个最小的不可再分的工作单元。 一个事务对应一套完整的业务操作。事务管理是指这些操作要么全部成功执行,要么全部回滚,从而保证数据的一致性和完整性。比如银行转账,需要保证转出和转入是一个原子操作。Spring提…...

社区版 IDEA 开发webapp 配置tomcat
1.安装tomcat 参考Tomcat配置_tomcat怎么配置成功-CSDN博客 2.构建webapp项目结构 新建一个普通项目 然后添加webapp的目录结构: main目录下新建 webapp 文件夹 webapp文件夹下新建WEB_INF文件夹 *WEB_INF目录下新建web.xml wenapp文件夹下再新建index.html …...
打 印 菱 形
本题要求你写个程序打印成菱形的形状。例如给定17个符号,要求按下列格式打印 **** *********所谓“菱形形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数从1开始先从小到大顺序递增ÿ…...

ffmpeg翻页转场动效的安装及使用
文章目录 前言一、背景二、选型分析2.1 ffmpeg自带的xfade滤镜2.2 ffmpeg使用GL Transition库2.3 xfade-easing项目 三、安装3.1、安装依赖([参考](https://trac.ffmpeg.org/wiki/CompilationGuide/macOS#InstallingdependencieswithHomebrew))3.2、获取…...

[RocketMQ] 发送重试机制与消费重试机制~
发送重试 RocketMQ 客户端发送消息时,由于网络故障等因素导致消息发送失败,这时客户端SDK会触发重试机制,尝试重新发送以达到调用成功的效果。 触发条件 客户端消息发送请求失败或超时。服务端节点处于重启或下线状态。服务端运行慢造成请…...

基于Redis的网关鉴权方案与性能优化
文章目录 前言一、微服务鉴权1.1 前端权限检查1.2 后端权限检查1.3 优缺点 二、网关鉴权2.1 接口权限存储至Redis2.2 网关鉴权做匹配 总结 前言 在微服务架构中,如何通过网关鉴权结合Redis缓存提升权限控制的效率与性能。首先,文章对比了两种常见的权限…...

计算机网络-L2TP VPN基础概念与原理
一、概述 前面学习了GRE和IPSec VPN,今天继续学习另外一个也很常见的VPN类型-L2TP VPN。 L2TP(Layer 2 Tunneling Protocol) 协议结合了L2F协议和PPTP协议的优点,是IETF有关二层隧道协议的工业标准。L2TP是虚拟私有拨号网VPDN&…...

Node.js day-01
01.Node.js 讲解 什么是 Node.js,有什么用,为何能独立执行 JS 代码,演示安装和执行 JS 文件内代码 Node.js 是一个独立的 JavaScript 运行环境,能独立执行 JS 代码,因为这个特点,它可以用来编写服务器后端…...

vue el-dialog实现可拖拉
el-dialog实现拖拉,每次点击度居中显示,以下贴出代码具体实现,我是可以正常拖拉并且每次度显示在中间,效果还可以,需要的可以丢上去跑跑 组件部分: <el-dialog:visible.sync"dialogVisible"…...
go配置文件
https://github.com/spf13/viper viper golang中常用的配置文件工具为viper库,是一个第三方库。viper功能: 解析JSON、TOML、YAML、HCL等格式的配置文件。监听配置文件的变化(WatchConfig),不需要重启程序就可以读到最新的值。...

C++ OpenGL学习笔记(2、绘制橙色三角形绘制、绿色随时间变化的三角形绘制)
相关文章链接 C OpenGL学习笔记(1、Hello World空窗口程序) 目录 绘制橙色三角形绘制1、主要修改内容有:1.1、在主程序的基础上增加如下3个函数1.2、另外在主程序外面新增3个全局变量1.3、编写两个shader程序文件 2、initModel()函数3、initS…...
项目搭建+删除(单/批)
一 : 删除没有单独的页面,在列表页面写 二 : 删除在列表的页面 1.删除(单/双)的按钮 ① : 在列表文档就绪函数的ajax里面,成功回调函数追加数据里写删除按钮 注意点 : 删除/修改/回显都是根据id来的,记得传id ② : 批删给批删按钮,定义批删的方法 one : 示例(单删) : //循环追…...
《小米创业思考》
《小米创业思考》是小米创始人雷军对小米创业历程的系统梳理和深度思考,蕴含着许多宝贵的创业经验与智慧,以下是主要内容: 创业初心与梦想 - 源于热爱与使命感:雷军及团队怀着对科技的热爱和让每个人享受科技乐趣的使命感创立小米…...

多种注意力机制详解及其源码
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...

VMWare 的克隆操作
零、碎碎念 VMWare 的这个克隆操作很简单,单拎出来成贴的目的是方便后续使用。 一、操作步骤 1.1、在“源”服务器上点右键,选择“管理--克隆” 1.2、选择“虚拟机的当前状态”为基础制作克隆,如下图所示,然后点击“下一页” 1.3、…...

Y3编辑器教程7:界面编辑器
文章目录 一、简介1.1 导航栏1.2 画板1.3 场景界面1.4 控件1.4.1 空节点1.4.2 按钮1.4.3 图片1.4.4 模型1.4.5 文本1.4.6 输入框1.4.7 进度条1.4.8 列表 1.5 元件1.5.1 简介1.5.2 差异说明1.5.3 元件实例的覆盖、还原与禁止操作1.5.4 迷雾控件 1.6 属性1.7 事件(动画…...

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具
本篇将带你实现一个评分统计工具,用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果,并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…...

run postinstall error, please remove node_modules before retry!
下载 node_modules 报错:run postinstall error, please remove node_modules before retry! 原因:node 版本出现错误,我的项目之前是在 12 下运行的。解决方法: 先卸载node_modules清除缓存将node版本切换到12重新下载即可...

详细解读TISAX认证的意义
详细解读TISAX认证的意义,犹如揭开信息安全领域的一颗璀璨明珠,它不仅代表了企业在信息安全管理方面的卓越成就,更是通往全球汽车供应链信任桥梁的关键一环。TISAX,即“Trusted Information Security Assessment Exchange”&#…...

【开源项目】数字孪生轨道~经典开源项目数字孪生智慧轨道——开源工程及源码
飞渡科技数字孪生轨道可视化平台,基于国产数字孪生引擎,结合物联网IOT、大数据、激光雷达等技术,对交通轨道进行超远距、高精度、全天侯的监测,集成轨道交通运营数据,快速准确感知目标,筑牢轨交运营生命线。…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...