连载中 10/18

传播行为七式:REQUIRED、REQUIRES_NEW、NESTED 的真实差别

2026-11-07 · 49 阅读 · 0 评论 · 0 赞

事务碰到事务,听谁的

方法 A(有事务)调用方法 B(也有 @Transactional),B 的事务是加入 A,还是另起炉灶?传播行为就是回答这个问题的。七种里,真正高频的是三式,其余四种了解即可。

三大主力对比

REQUIRED(默认)  有事务就加入,没有就新开
                  → 内外同一个事务,任何一方回滚,全体陪葬

REQUIRES_NEW      挂起外层事务,开一个全新的
                  → 两个独立事务:内层回滚不影响外层,
                    外层回滚也带不走内层已提交的数据

NESTED            在当前事务里设 Savepoint 存档点
                  → 内层回滚退回存档点,外层照常;
                    但外层若回滚,内层跟着没(它是存档,不是独立事务)

一句话记忆:REQUIRED 是绑在一起,REQUIRES_NEW 是各过各的,NESTED 是游戏存档。

经典场景:审计日志必须独立落库

业务操作失败要回滚,但「谁在什么时候做了失败操作」的日志必须留下来——日志方法标 REQUIRES_NEW:外层业务回滚,内层日志已独立提交,带不走。反过来,批量导入要「整批可放弃、单条可跳过」——单条处理套 NESTED,坏一条回滚到存档点继续下一条,整批的去留由外层统一裁决。注意 NESTED 依赖 JDBC Savepoint,JPA 体系不支持。

两笔成本,心里有数

其一,连接占用:REQUIRES_NEW 挂起外层时另拿一条连接,内外并行占用两条;嵌套一多或连接池偏小,池被借空直接卡死。其二,锁冲突死锁:外层事务改了某行还没提交(行锁在手),内层 REQUIRES_NEW 再去改同一行——自己等自己,经典死锁。看到「事务方法内嵌 REQUIRES_NEW 且操作同一批数据」,先想锁。

其余四式速览

SUPPORTS——有事务就加入,没有就非事务跑;NOT_SUPPORTED——挂起当前事务,非事务执行;MANDATORY——必须有外层事务,否则抛异常(保护性声明);NEVER——不许有事务,有就抛异常。后四种常见于框架代码做约束声明。

实现彩蛋:挂起就是连接换手

挂起在源码里的样子:把外层的 ConnectionHolder 从 ThreadLocal 解绑、封进 SuspendedResourcesHolder 存起来,内层新拿连接绑定;内层结束后解绑、再把外层的绑回去。传播行为切换的本质,就是 ThreadLocal 上的连接换手。至此事务三篇闭环:原理(第 8 篇)→ 失效(第 9 篇)→ 嵌套(本篇)。

下一篇转场注入体系:@Autowired 与 @Resource 的门道,以及集合注入为什么能一次拿到所有实现。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#Spring#事务#传播行为#REQUIRES_NEW#NESTED

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10134 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9899 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9329 阅读 · 21 评论 · 287 赞