Java-138 深入浅出 MySQL Spring Boot 事务传播机制全解析:从 REQUIRED 到 NESTED 的实战详解 传播机制原理
点一下关注吧!!!非常感谢!!持续更新!!!
🚀 AI篇持续更新中!(长期更新)
AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布!“快的模型 + 深度思考模型 + 实时路由”,持续打造实用AI工具指南!📐🤖
💻 Java篇正式开启!(300篇)
目前2025年09月29日更新到:
Java-136 深入浅出 MySQL Spring Boot @Transactional 使用指南:事务传播、隔离级别与异常回滚策略
MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
📊 大数据板块已完成多项干货更新(300篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
事务传播
参考来源
- https://juejin.cn/post/7106158883055353870
简单介绍
(对应注解的:propagation)事务的传播行为,是指程序在调用的过程中,如果调用方已经创建了事务,那么被调用的服务将如何处理事务的一种特征,如下图所示:
PROPAGATION_REQUIRED
这是注解默认的值,它具有以下的特点:
● 如果当前没有物理事务,那么 Spring 会创建一个事务出来
● 如果已经有了一个物理事务,那么就加入这个事务
● 每一个 PROGAGATION_REQUIRED 都对应一个逻辑事务,这些逻辑事务都会加入到同一个物理事务
● 每个逻辑事务都有自己的作用范围,但是在这种传播机制下,所有这些范围都会被映射到同一个物理事务中
正是因为所有的逻辑事务都在同一个物理事务上,当物理事务上任何一个逻辑进行回滚,那么这个物理事务就会回滚。
PROPAGATION_REQUIRES_NEW
PROPAGATION_REQUIRES_NEW 是 Spring 事务传播行为中的一种重要级别,它表示无论当前是否存在事务,Spring 总会创建一个新的独立的物理事务。在这种传播级别下,内部事务与外部事务完全隔离,具有以下关键特性:
-
独立事务特性:
- 内部事务会启动一个全新的数据库连接
- 拥有独立的事务ID
- 使用独立的事务隔离级别
- 维护自身的事务状态
-
与外部事务的关系:
- 如果外部事务存在,会先将其挂起
- 内部事务完成后才会恢复外部事务
- 内部事务的提交或回滚不会影响外部事务
-
典型应用场景:
@Transactional(propagation = Propagation.REQUIRED)public void outerMethod() {// 外部事务操作...innerMethod(); // 调用内嵌方法// 更多外部事务操作...}@Transactional(propagation = Propagation.REQUIRES_NEW)public void innerMethod() {// 这些操作会在独立的事务中执行}
-
注意事项:
- 每个 REQUIRES_NEW 事务都会占用新的数据库连接
- 可能导致连接池资源紧张
- 适合用于需要独立提交的日志记录、审计等非核心业务
-
与其他传播行为的区别:
- 不同于 PROPAGATION_REQUIRED(加入当前事务)
- 不同于 PROPAGATION_NESTED(嵌套事务)
- 不同于 PROPAGATION_NOT_SUPPORTED(非事务执行)
这种传播级别特别适合那些需要确保执行成功,且执行结果不应影响主业务流程的操作场景。
这种情况下,每个物理事务都有自己的数据库连接,也就是说,当创建内部物理事务的时候,会同步为这个事务绑定一个新的数据库连接,当内部的物理事务运行的时候,外部的物理事务就会暂停执行(保持连接),当内部的物理事务提交之后,外部的事务进行回复,继续执行或者回滚。
(这种情况下,即使内部的物理事务回滚了,外部的事务也可以顺利提交执行;如果外部事务回滚了,也不会影响内部的事务提交执行。)
PROPAGATION_NESTED
PROPAGATION_NESTED 是 Spring 事务传播机制中的一种特殊传播行为,它与 PROPAGATION_REQUIRED 类似,但具有更精细的回滚控制能力。
主要特点:
- 如果当前存在事务,则创建一个嵌套事务(内部事务),该嵌套事务会设置一个 SAVEPOINT(保存点)
- 嵌套事务的回滚不会影响外部事务,只会回滚到保存点位置
- 外部事务的回滚会导致嵌套事务也回滚
- 如果当前没有事务,则与 PROPAGATION_REQUIRED 行为相同
典型应用场景:
- 需要记录操作日志的场景(日志记录失败不应影响主业务)
- 批量处理中的单条记录处理(某条记录处理失败不应中断整个批次)
- 需要部分回滚的复杂业务逻辑
示例:
@Transactional(propagation = Propagation.REQUIRED)
public void batchProcess() {// 主业务逻辑for (Item item : items) {try {processItem(item); // 嵌套事务处理单条记录} catch (Exception e) {// 单条记录失败不影响其他记录log.error("Process item failed", e);}}
}@Transactional(propagation = Propagation.NESTED)
public void processItem(Item item) {// 处理单条记录的业务逻辑
}
注意事项:
- 嵌套事务与 JDBC 3.0 的保存点机制实现相关
- 不是所有数据库都支持保存点机制
- JTA 事务管理器不支持此传播行为
PROPAGATION_MANDATORY
PROPAGATION_MANDATORY 是 Spring 事务传播行为中的一种,表示当前方法必须在一个已存在的物理事务中运行。如果当前没有活动的事务,将会抛出 IllegalTransactionStateException
异常。
主要特点
- 事务依赖性:该方法不能独立运行,必须依赖于调用方提供的事务上下文
- 异常机制:如果没有活动事务,会立即抛出异常而不是创建一个新事务
- 事务继承:会沿用调用方的事务属性(如隔离级别、超时设置等)
典型应用场景
- 核心业务方法:如资金转账操作必须在一个事务中执行
- 数据一致性要求高的操作:如订单系统中的库存扣减
- 作为更大事务的一部分:如电子商务中的支付流程
代码示例
@Service
public class PaymentService {@Transactional(propagation = Propagation.MANDATORY)public void processPayment(Order order) {// 支付处理逻辑// 如果这个方法被没有事务的代码调用,会抛出异常}
}
与其他传播行为的区别
- 与 REQUIRED 不同:REQUIRED 在没有事务时会新建一个,而 MANDATORY 会抛出异常
- 与 SUPPORTS 不同:SUPPORTS 可以在没有事务时运行,而 MANDATORY 必须有事务
- 与 NEVER 相反:NEVER 要求不能有事务,MANDATORY 要求必须有事务
注意事项
- 适用于需要强制事务保障的重要业务方法
- 调用方必须确保已经开启了事务
- 可以配合其他事务属性(如隔离级别、只读标记)一起使用
PROPAGATION_NEVER
定义与作用
PROPAGATION_NEVER
是 Spring 事务传播行为中的一种策略,表示方法必须在非事务环境下执行。如果当前已经存在事务上下文,Spring 将直接抛出 IllegalTransactionStateException
异常,强制中止操作。
典型特征
- 严格非事务要求:被标记的方法必须确保在没有任何事务(包括物理事务和嵌套事务)的环境中运行
- 显式异常提示:与
PROPAGATION_NOT_SUPPORTED
不同,它不会挂起已有事务,而是直接拒绝执行 - 事务边界检查:在方法执行前会进行严格的事务存在性检查
使用场景
- 执行不需要事务的读取操作(如缓存加载)
- 运行明确不能有事务影响的特殊方法(如某些审计日志记录)
- 在事务边界外执行统计计算等操作
- 作为事务与非事务代码之间的显式隔离标记
代码示例
@Transactional(propagation = Propagation.NEVER)
public void loadReferenceData() {// 此方法必须确保在无事务环境下执行cacheManager.reloadAll();
}
注意事项
- 调用链上必须确保没有
@Transactional
注解的传播 - 需要与事务模板(TransactionTemplate)等显式事务操作隔离使用
- 在测试环境中需要特别注意模拟非事务环境
- 与
REQUIRES_NEW
等事务传播行为组合使用时会产生冲突
异常处理
当检测到现有事务时,Spring 会抛出:
org.springframework.transaction.IllegalTransactionStateException:
Existing transaction found for transaction marked with propagation 'never'
建议在调用方做好异常捕获和处理逻辑,或者通过前置条件检查确保执行环境符合要求。
PROPAGATION_SUPPORTS
PROPAGATION_SUPPORTS
是 Spring 事务传播机制中的一种传播行为,它定义了方法在事务上下文中的执行方式。具体行为规则如下:
-
存在物理事务时:
- 如果当前已经存在一个事务上下文(即调用方法处于一个事务范围内),则该方法会加入这个现有的事务
- 此时方法的所有操作都将成为现有事务的一部分,遵循现有事务的隔离级别和超时设置
- 如果外层事务回滚,该方法所做的所有修改也会被回滚
-
不存在物理事务时:
- 如果当前没有事务上下文,则该方法会以非事务的方式执行
- 每个数据库操作都会自动提交,不会参与任何事务管理
- 此时方法执行的SQL语句将具有自动提交的特性
典型应用场景:
- 适用于那些既可以在事务中运行,也可以不在事务中运行的非核心业务方法
- 常用于查询操作,因为查询通常不需要事务支持
- 适合作为服务层方法的默认传播行为,特别是那些不涉及数据修改的操作
示例代码:
@Service
public class UserService {@Transactional(propagation = Propagation.SUPPORTS)public User getUserById(Long id) {// 该方法可以在事务中执行,也可以不在事务中执行return userRepository.findById(id);}
}
注意事项:
- 当方法中存在多个数据库操作时,使用
PROPAGATION_SUPPORTS
可能导致数据不一致的风险 - 不适合用于必须保证原子性的关键业务操作
- 与
PROPAGATION_REQUIRED
不同,它不会主动创建新的事务
与其他传播行为的比较:
- 比
PROPAGATION_REQUIRED
更灵活,不会强制要求事务 - 比
PROPAGATION_NOT_SUPPORTED
更温和,允许在存在事务时参与其中 - 与
PROPAGATION_MANDATORY
相反,后者要求必须存在事务
PROPAGATION_NOT_SUPPORTED
PROPAGATION_NOT_SUPPORTED
是 Spring 事务传播行为中的一种特殊模式,它表示当前方法不应在事务上下文中运行。当使用此传播行为时:
-
事务挂起机制:
- 如果调用此方法时已经存在一个活动事务(物理事务),Spring 会将该事务挂起(suspend)
- 事务管理器会将该事务的相关资源(如数据库连接)与当前线程解绑
- 事务状态信息会被保存在内存中,以便后续恢复
-
非事务执行:
- 方法会在没有事务的上下文中执行
- 所有数据库操作将以自动提交模式(auto-commit)运行
- 每个SQL语句都将被立即提交,不会参与任何事务
-
事务恢复:
- 方法执行完毕后,Spring会检查是否有被挂起的事务
- 如果有,会将之前挂起的事务恢复(resume)
- 事务资源会重新绑定到当前线程
- 后续操作将继续在原有事务上下文中执行
典型应用场景:
- 日志记录操作:当需要记录日志到数据库,但不希望日志记录操作影响主业务事务时
- 非关键性操作:如发送通知消息等非核心业务操作
- 性能优化:某些不需要事务保证的只读操作,可以避免事务开销
示例代码:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void logOperation(String message) {// 此方法会在非事务上下文中执行logRepository.save(new LogEntry(message));
}
注意事项:
- 使用此传播行为时,方法中的数据库操作将不具备原子性
- 要谨慎使用,确保业务确实不需要事务保证
- 在分布式事务环境中行为可能更加复杂