一、SUPPORTS 核心定义(必记)
1. 注解写法(必须手动指定,非默认)
java
运行
@Transactional(propagation = Propagation.SUPPORTS)
2. 极简口诀(和REQUIRED对比记忆,一辈子不忘)
REQUIRED:有则加入,无则新建(无事务时主动创建事务)SUPPORTS:有则加入,无则无事务(无事务时就「裸奔」执行,不创建任何事务)
3. 完整严谨规则
当被
@Transactional(propagation=SUPPORTS)标记的方法执行时:- 检查当前执行环境是否存在事务;
- ✔️ 如果当前已有事务 → 该方法加入到这个已存在的事务中,成为事务的一部分(和
REQUIRED这一步的行为完全一致); - ✔️ 如果当前没有事务 → 该方法不会新建任何事务,直接以「无事务」的方式执行代码;
✅ 二、REQUIRED vs SUPPORTS 核心对比(重中之重,一张表看懂)
这是两个传播机制的唯一区别,也是核心考点,一定要吃透:
| 传播机制 | 有事务时行为 | 无事务时行为 | 核心特点 |
|---|---|---|---|
REQUIRED(默认) |
加入已有事务 | 新建事务执行 | 「强制性」事务,一定有事务包裹 |
SUPPORTS |
加入已有事务 | 无事务执行 | 「支持性」事务,有没有事务都能执行,随外层环境而定 |
💡 关键结论:两者仅在「外层无事务」时行为不同,外层有事务时行为完全一样!
✅ 三、准备测试代码(复用你熟悉的结构,无冗余)
和上一节
REQUIRED的示例完全复用,仅修改事务传播机制,降低理解成本,所有规则完全贴合真实开发:- 两个核心方法,都标记为
SUPPORTS传播机制; deductStock()依然手动抛出RuntimeException,模拟业务执行失败,用于验证事务回滚规则;- 事务只对增 / 删 / 改数据库操作生效,查询方法无事务意义,这里依然用「创建订单 + 扣减库存」模拟真实业务。
java
运行
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
// 事务方法1:创建订单,SUPPORTS传播机制
@Transactional(propagation = Propagation.SUPPORTS)
public void createOrder() {
System.out.println("执行逻辑:向数据库插入【订单】数据");
// 真实代码:mapper.insert(order);
}
// 事务方法2:扣减库存,SUPPORTS传播机制 + 模拟异常
@Transactional(propagation = Propagation.SUPPORTS)
public void deductStock() {
System.out.println("执行逻辑:修改数据库的【商品库存】数据");
// 真实代码:mapper.update(stock);
throw new RuntimeException("扣减库存失败!库存不足"); // 手动抛异常
}
}
✅ 四、场景一:外层方法【无事务】,调用SUPPORTS内层方法(核心差异场景)
这是
SUPPORTS和REQUIRED唯一不一样的场景,也是SUPPORTS的核心特性,开发中 90% 的坑都在这里!1. 新增无事务外层方法
java
运行
// 无事务的外层方法:无任何@Transactional注解
public void doBizWithoutTx() {
this.createOrder(); // 调用SUPPORTS方法
this.deductStock(); // 调用SUPPORTS方法(抛异常)
}
2. 执行结果 + 事务深度分析
✅ 最终结果:数据库中「订单数据插入成功」、「库存扣减操作执行了但抛异常」,两个操作都不会回滚!
✅ 核心分析(逐行拆解,必须看懂):
- 外层方法无事务,执行环境「无事务」;
- 调用
createOrder()(SUPPORTS)→ 无事务 → 无事务执行,数据库操作是「自动提交」模式,订单插入后立刻写入数据库,没有事务保护; - 调用
deductStock()(SUPPORTS)→ 无事务 → 无事务执行,库存扣减的 SQL 先执行,然后抛出异常; - ⚠️ 关键坑点:无事务环境下,抛出任何异常都不会触发回滚!因为回滚是「事务的能力」,没有事务,数据库操作执行后就直接提交了,无法回滚。
✅ 和 REQUIRED 的对比(必看)
同样是「外层无事务」的场景:
REQUIRED:两个方法会各自新建独立事务,一个成功提交、一个失败回滚;SUPPORTS:两个方法无事务执行,全部自动提交,抛异常也不会回滚;
✅ 五、场景二:外层方法【有事务】,调用SUPPORTS内层方法(行为一致场景)
这是
SUPPORTS和REQUIRED完全相同的场景,也是SUPPORTS的核心价值所在,务必记住:外层有事务时,SUPPORTS = REQUIRED!1. 新增有事务外层方法
java
运行
// 有事务的外层方法:默认REQUIRED传播机制
@Transactional
public void doBizWithTx() {
this.createOrder(); // 调用SUPPORTS方法
this.deductStock(); // 调用SUPPORTS方法(抛异常)
}
2. 执行结果 + 事务深度分析
✅ 最终结果:数据库中「订单无插入、库存无修改」,两个操作全部回滚!
✅ 核心分析(和 REQUIRED 一模一样):
- 外层方法加了
@Transactional,执行时新建了一个主事务 T; - 调用
createOrder()(SUPPORTS)→ 当前有事务 T → 加入主事务 T,订单插入成为事务的一部分; - 调用
deductStock()(SUPPORTS)→ 当前有事务 T → 加入主事务 T,库存扣减也成为事务的一部分; - 方法抛出异常后,整个主事务 T 全局回滚,事务内所有操作全部撤销;
✅ 六、SUPPORTS 避坑 3 个核心注意事项(开发必看,高频踩坑)
⚠️ 注意 1:无事务时,任何异常都不会触发回滚(重中之重)
这是
SUPPORTS最容易踩坑的点,没有之一:SUPPORTS的方法,只有在「外层有事务」的情况下,才具备事务的回滚能力;如果外层无事务,这个方法就是「裸奔执行」,哪怕抛了RuntimeException、手动加了try-catch,数据库操作都不会回滚!
⚠️ 注意 2:SUPPORTS 永远不会主动「新建事务」
这个传播机制的名字是
无论任何情况,被
SUPPORTS(支持),意思是:它只支持「使用别人的事务」,自己从不创建事务。
SUPPORTS标记的方法,都不会主动新建事务,这是和REQUIRED的本质区别。⚠️ 注意 3:事务的所有属性,都「继承外层事务」
当
SUPPORTS的方法加入外层事务后,它会完全继承外层事务的所有属性:- 隔离级别、超时时间、只读属性、回滚规则等,都和外层事务一致;
- 事务的提交 / 回滚,完全由外层事务决定,内层方法无权单独提交或回滚。
✅ 七、SUPPORTS 正确使用场景(什么时候用?核心价值)
学完规则,一定要知道「在哪用」,
SUPPORTS不是随便用的,它有明确的适用场景,这也是 Spring 设计这个传播机制的核心目的,记住:SUPPORTS 天生为「查询方法」而生!✅ 适用场景 1:纯查询的业务方法(99% 的使用场景)
开发中我们有大量的查询方法(比如:查询订单详情、查询商品列表、查询用户信息),这类方法的特点:
- 只有
SELECT语句,没有增删改,不需要事务保护; - 但这些查询方法,可能会被「有事务的业务方法」调用(比如:下单时先查询库存,再扣减库存);
此时给查询方法加
@Transactional(propagation=SUPPORTS)是最佳实践:- 如果被「无事务的方法」调用 → 无事务执行,查询效率更高(事务会加锁,无事务查询更快);
- 如果被「有事务的方法」调用 → 加入事务,保证查询到的数据是「事务内的一致性数据」(避免脏读);
✅ 适用场景 2:可独立执行、也可被事务包裹执行的通用方法
比如一个「修改用户积分」的方法,它既可以被「下单流程(有事务)」调用,也可以被「手动签到(无事务)」调用:
- 被下单流程调用 → 加入事务,积分修改和订单、库存一起提交 / 回滚;
- 被手动签到调用 → 无事务执行,积分修改后直接提交,不影响其他操作;
这种「复用性高」的方法,用
SUPPORTS最合适。✅ 八、完整总结(所有核心要点,浓缩记忆)
✔️ 核心口诀
SUPPORTS → 有则加入,无则无事务✔️ 核心差异(和 REQUIRED)
- 外层有事务 → 两者行为完全一致,都加入外层事务;
- 外层无事务 → REQUIRED 新建事务,SUPPORTS 无事务执行(唯一区别)。
✔️ 核心特性
- 永远不会主动新建事务;
- 无事务时抛异常不回滚,有事务时抛异常全局回滚;
- 继承外层事务的所有属性。
✔️ 最佳使用场景
所有只读的查询方法优先使用
SUPPORTS,兼顾「执行效率」和「事务一致性」;其次是「可独立执行、也可被事务包裹」的通用业务方法。✔️ 避坑核心
只要看到
SUPPORTS,第一反应就是:这个方法有没有事务,完全看调用它的外层方法有没有加事务注解。
浙公网安备 33010602011771号