【深入解剖Spring事务管理】原理、传播机制与12大失效场景避坑指南
Spring 事务管理是构建健壮企业应用的核心,其核心原理、@Transactional注解的工作机制、传播行为及失效场景是开发者必须掌握的关键点。下面我将逐一深入解析:
一、Spring 事务管理的核心原理
Spring 事务的本质是 通过 AOP(面向切面编程) 对目标方法进行增强,具体流程如下:
代理对象创建:
- 当使用
@Transactional注解时,Spring 会为目标 Bean(如UserServiceImpl)创建代理对象(JDK 动态代理或 CGLIB 代理)。 - 调用
userService.updateUser()时,实际调用的是代理对象的方法。
- 当使用
事务拦截器(TransactionInterceptor):
- 代理对象内部包含一个
TransactionInterceptor。 - 在目标方法执行前,拦截器通过
PlatformTransactionManager(如DataSourceTransactionManager)开启事务(获取数据库连接,设置autoCommit=false)。
- 代理对象内部包含一个
目标方法执行:
- 执行原始方法逻辑(包含数据库操作)。
事务提交/回滚:
- 方法成功执行 → 提交事务(
connection.commit())。 - 抛出未捕获的异常 → 回滚事务(
connection.rollback())。
- 方法成功执行 → 提交事务(
// 伪代码:TransactionInterceptor 逻辑
public Object invoke(MethodInvocation invocation) {
TransactionStatus status = transactionManager.beginTransaction(); // 开启事务
try {
Object result = invocation.proceed(); // 执行目标方法
transactionManager.commit(status); // 提交事务
return result;
} catch (RuntimeException e) {
transactionManager.rollback(status); // 回滚事务
throw e;
}
}
二、@Transactional 注解工作机制
注解解析:
- Spring 扫描 Bean 时识别
@Transactional,为类或方法生成代理。 - 注解属性(如
propagation,isolation,rollbackFor)被解析为TransactionAttribute。
- Spring 扫描 Bean 时识别
事务属性绑定:
- 方法执行时,
TransactionInterceptor根据注解属性配置事务行为(如传播机制、隔离级别)。
- 方法执行时,
事务管理器协调:
- 通过
PlatformTransactionManager管理事务生命周期(开启、提交、回滚)。
- 通过
三、事务传播机制(Propagation Behavior)
定义多个事务方法相互调用时的事务边界规则,共 7 种类型:
| 传播行为类型 | 说明 | 适用场景 |
|---|---|---|
| REQUIRED (默认) | 当前有事务则加入,没有则新建 | 大多数业务逻辑(如订单创建) |
| REQUIRES_NEW | 无论当前是否有事务,都新建事务(原事务挂起) | 日志记录(需独立提交) |
| SUPPORTS | 当前有事务则加入,没有则以非事务运行 | 查询方法(可适应事务环境) |
| NOT_SUPPORTED | 以非事务方式执行,挂起当前事务(存在时) | 发送消息(避免事务阻塞) |
| MANDATORY | 必须在已有事务中运行,否则抛异常 | 强制要求事务上下文 |
| NEVER | 必须在非事务环境下执行,否则抛异常 | 禁止事务的方法(如初始化操作) |
| NESTED | 在当前事务内嵌套子事务(可独立回滚),需 JDBC 3.0 驱动支持 | 复杂业务的分步操作(如订单子项) |
经典场景对比:
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder() {
// 主订单逻辑
orderItemService.addItem(); // 调用子事务方法
}
}
@Service
public class OrderItemService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addItem() {
// 订单项逻辑(独立事务,失败不影响主订单)
}
}
四、事务失效的 12 个常见场景
非 public 方法
- 原因:Spring AOP 无法代理私有方法(CGLIB 通过继承实现代理)。
- 解决:将方法改为
public。
自调用问题
- 原因:类内部方法调用(如
this.update())不经过代理对象。 - 解决:
@Autowired
private UserService selfProxy; // 注入自身代理 public void save() {
selfProxy.update(); // 通过代理调用
}
- 原因:类内部方法调用(如
异常类型不匹配
- 原因:默认只回滚
RuntimeException和Error,捕获Exception不会回滚。 - 解决:明确指定回滚异常:
@Transactional(rollbackFor = Exception.class)
- 原因:默认只回滚
手动捕获异常未抛出
- 错误示例:
try {
userDao.insert();
} catch (Exception e) {
// 未抛出 → 事务提交!
}
- 错误示例:
多线程调用
- 原因:事务信息存储在
ThreadLocal,新线程无法获取上下文。 - 解决:避免跨线程事务操作。
- 原因:事务信息存储在
数据库引擎不支持事务
- 如 MySQL 的 MyISAM 引擎不支持事务(需使用 InnoDB)。
未启用事务管理
- 缺失注解:
@EnableTransactionManagement(Spring Boot 中自动配置)。
- 缺失注解:
Bean 未被 Spring 管理
- 原因:类未标注
@Service/@Component。
- 原因:类未标注
Checked Exception 未配置回滚
- 原因:Checked Exception(如
IOException)默认不回滚。 - 解决:显式配置
@Transactional(rollbackFor = IOException.class)。
- 原因:Checked Exception(如
传播行为配置为 NOT_SUPPORTED/NEVER
- 强制以非事务方式运行。
方法内启动新线程异步操作
- 异步操作脱离原事务上下文(需用
@Async+@Transactional单独管理)。
- 异步操作脱离原事务上下文(需用
嵌套事务回滚不当
- 嵌套事务(NESTED)需外层捕获内层异常,否则整体回滚。
关键总结
| 维度 | 要点 |
|---|---|
| 代理机制 | JDK 动态代理或 CGLIB 生成代理对象 |
| 事务管理器 | PlatformTransactionManager 是核心接口 |
| 传播行为 | REQUIRED(默认)、REQUIRES_NEW、NESTED 最常用 |
| 失效场景 | 自调用、异常处理、非 public 方法是高频踩坑点 |
| 调试技巧 | 开启 debug 日志:logging.level.org.springframework.transaction=DEBUG |
最佳实践:
- 始终在
@Service层的 public 方法上使用@Transactional。- 明确指定
rollbackFor(如rollbackFor = Exception.class)。- 对嵌套事务使用
Propagation.NESTED时,确保数据库驱动支持保存点(Savepoint)。- 避免在事务方法中处理耗时操作(如 RPC 调用),减少数据库连接占用时间。
理解这些机制能有效避免生产环境的事务陷阱,确保数据一致性。
【深入解剖Spring事务管理】原理、传播机制与12大失效场景避坑指南的更多相关文章
- Spring 事务管理原理探究
此处先粘贴出Spring事务需要的配置内容: 1.Spring事务管理器的配置文件: 2.一个普通的JPA框架(此处是mybatis)的配置文件: <bean id="sqlSessi ...
- 聊聊Spring事务控制策略以及@Transactional失效问题避坑
大家好,又见面了. 在大部分涉及到数据库操作的项目里面,事务控制.事务处理都是一个无法回避的问题.比如,需要对SQL执行过程进行事务的控制与处理的时候,其整体的处理流程会是如下的示意: 首先是要开启事 ...
- Spring事务管理机制的实现原理-动态代理
之前在做项目中遇到spring无法进行事务代理问题,最后发现是因为没有写接口,原因当时明白了,看到这篇文章写的清楚些,转过来 我们先来分析一下Spring事务管理机制的实现原理.由于Spring内置A ...
- Spring系列.事务管理原理简析
Spring的事务管理功能能让我们非常简单地进行事务管理.只需要进行简单的两步配置即可: step1:开启事务管理功能 @Configuration //@EnableTransactionManag ...
- spring 事务管理机制
1. spring 事务管理抽象 spring 的事务策略机制的核心就是 org.springframework.transaction.PlatformTransactionManager 接口. ...
- 【Java EE 学习 52】【Spring学习第四天】【Spring与JDBC】【JdbcTemplate创建的三种方式】【Spring事务管理】【事务中使用dbutils则回滚失败!!!??】
一.JDBC编程特点 静态代码+动态变量=JDBC编程. 静态代码:比如所有的数据库连接池 都实现了DataSource接口,都实现了Connection接口. 动态变量:用户名.密码.连接的数据库. ...
- spring事务管理器设计思想(二)
上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...
- Spring事务管理(转)
1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...
- [Spring框架]Spring 事务管理基础入门总结.
前言:在之前的博客中已经说过了数据库的事务, 不过那里面更多的是说明事务的一些锁机制, 今天来说一下Spring管理事务的一些基础知识. 之前的文章: [数据库事务与锁]详解一: 彻底理解数据库事务一 ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
随机推荐
- WPF 制作三个点从左到右过渡隐藏显示
Code: <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/win ...
- API接口调用--历史上的今天(v1.0)
历史上的今天 参考(聚合数据):https://www.juhe.cn/docs/api/id/63 事件列表(v1.0) 接口地址: http://api.juheapi.com/japi/toh ...
- 工具 | StarCodeSecurity
0x00 简介 StarCodeSecurity是一款图形化的代码审计工具. 下载地址: StarCodeSecurity下载:StarCodeSecurity下载 0x01 功能说明 支持对规则进行 ...
- 【记录】LaTeX|Overleaf中ACM的LaTex模板的图片引用出现问号
问题 单张图片引用,出现如下问题: 出问题的LaTeX部分: As is shown in Figure~\ref{img:result}: \begin{figure}[h] \centering ...
- vue3 基础-父子组件间如何通过事件通信
前几篇讨论的父子组件间如何进行传数据的话题. 即父组件在调用子组件的时候, 通过自定义属性 (v-bind) 的方式传递数据, 同时子组件通过 props 属性进行接收. 子组件可以对数据进行各种校验 ...
- Python基础 - 文件处理(下)
主要是介绍两个文件处理的内置模块 os, pathlib. 上篇对文件的读写基本搞定了. 当然, 因为我做数据的嘛, 我的日常并不是简单的读写下文件, 而是重在读取数据后, 各种复杂的操作. 用到的更 ...
- 使用Node.js打造自己的Git版本控制系统
@charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...
- git reset回滚未提交的更改和覆盖分支
摘要:介绍git reset使用技巧:回滚本地所有未提交的更改,用一个分支覆盖另一个分支. git回滚本地所有未提交的更改可以使用命令 git reset,它的功能是强制覆盖本地文件到指定分支.切 ...
- obs学习之4——枚举设备、选择设备
obs学习之4--枚举设备.选择设备
- 团队如何限制合适的在制品(WIP)数量
看板之父David Anderson曾说过" 看板的本质是一个很朴素的思想:在制品必须被限制."但对于团队来说,确定一个合适的在制品限制可能是件棘手的事. 在 <看板快速启动 ...