Spring 源码系列(26): 事务传播行为源码
2026/9/5 11:34:03 网站建设 项目流程

📌 阅读前提示:第 25 篇看到TransactionInterceptor在业务方法前后管理事务。本篇深入事务最核心、也最容易考糊的概念——传播行为(Propagation)。当你在一个事务方法里调用另一个事务方法,Spring 怎么决定「新建事务」还是「加入已有事务」?答案在AbstractPlatformTransactionManager.getTransaction


一、引子:为什么需要传播行为

现实中常出现「外层方法开事务,内层方法也标了 @Transactional」的场景。内层是复用外层事务自己新开一个,还是干脆不事务?这就是传播行为要回答的。

@Transactional(propagation=Propagation.REQUIRED)// 默认publicvoidouter(){inner();}@Transactional(propagation=Propagation.REQUIRES_NEW)publicvoidinner(){/* ... */}

二、七种传播行为一览

行为含义
REQUIRED(默认)有就加入,没有就新建
REQUIRES_NEW挂起当前事务,新建一个独立事务
NESTED在当前事务内开嵌套保存点(仅 JDBC 支持)
SUPPORTS有事务就加入,没有就以非事务执行
NOT_SUPPORTED挂起当前事务,以非事务执行
NEVER必须在非事务环境,否则抛异常
MANDATORY必须已有事务,否则抛异常

三、源码追踪:getTransaction 的决策

// AbstractPlatformTransactionManager.java@OverridepublicfinalTransactionStatusgetTransaction(@NullableTransactionDefinitiondefinition){// ① 已存在事务?if(isExistingTransaction(transaction)){returnhandleExistingTransaction(definition,transaction,debugEnabled);// ★ 已有事务分支}// ② 无事务时,按定义处理if(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_MANDATORY){thrownewIllegalTransactionStateException("无现有事务,MANDATORY 不允许");}elseif(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRED||definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRES_NEW||definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NESTED){// 挂起外层 → 新建事务SuspendedResourcesHoldersuspendedResources=suspend(null);returnstartTransaction(definition,transaction,debugEnabled,suspendedResources);}else{// SUPPORTS / NOT_SUPPORTED / NEVER → 非事务执行returnprepareTransactionStatus(definition,null,true,newSynchronization,debugEnabled,null);}}

3.1 已有事务时的关键分支

privateTransactionStatushandleExistingTransaction(TransactionDefinitiondefinition,Objecttransaction,booleandebugEnabled){intpropagation=definition.getPropagationBehavior();if(propagation==PROPAGATION_NEVER){thrownewIllegalTransactionStateException("已存在事务,NEVER 不允许");}if(propagation==PROPAGATION_NOT_SUPPORTED){Objectsuspended=suspend(transaction);// 挂起现有事务returnprepareTransactionStatus(...非事务...);}if(propagation==PROPAGATION_REQUIRES_NEW){Objectsuspended=suspend(transaction);// ★ 挂起外层returnstartTransaction(definition,transaction,debugEnabled,suspended);// ★ 全新事务}if(propagation==PROPAGATION_NESTED){if(useSavepointForNestedTransaction()){DefaultTransactionStatusstatus=prepareTransactionStatus(...);status.createAndHoldSavepoint();// ★ 创建保存点(嵌套)returnstatus;}}// PROPAGATION_REQUIRED / SUPPORTS / (默认) → 加入现有事务returnprepareTransactionStatus(definition,transaction,false,newSynchronization,debugEnabled,null);}

📌 结论REQUIRED加入现有事务(共享连接)、REQUIRES_NEW挂起外层开新事务(独立提交/回滚)、NESTED用保存点(外层回滚则内层也回滚,内层回滚不影响外层)。


四、三种典型行为对比

行为与外层关系内层异常影响外层?外层异常影响内层?
REQUIRED同一事务是(一起回滚)
REQUIRES_NEW完全独立
NESTED同一连接 + 保存点是(内层回滚不波及外层)

⚠️ REQUIRES_NEW vs NESTEDREQUIRES_NEW是两个物理事务,互不影响;NESTED是同一物理事务内的保存点,外层提交内层才生效,外层回滚内层必回滚。


五、事务传播行为决策图


六、常见误区

误区正解
REQUIRED 每次都新建事务不,有就加入,无才新建
REQUIRES_NEW 和 NESTED 一样否,前者独立物理事务,后者同一连接保存点
NESTED 所有数据源都支持仅 JDBC 支持保存点,JTA 不支持
内层回滚一定导致外层回滚仅 REQUIRED/NESTED;REQUIRES_NEW 不会
传播行为在提交时判定不,在getTransaction进入时就已决策

🧪 面试题自测

  1. 七种传播行为中,哪些会新建事务、哪些加入、哪些非事务?
  2. REQUIREDREQUIRES_NEW的本质区别?
  3. NESTED的保存点机制是什么?有何限制?
  4. getTransaction如何判断「已有事务」?
  5. MANDATORYNEVER分别在什么情况下抛异常?
  6. 内层REQUIRES_NEW异常,外层REQUIRED会回滚吗?

🔧 Debug 小技巧

AbstractPlatformTransactionManager.getTransaction断点,分别用REQUIREDREQUIREDREQUIREDREQUIRES_NEW两种场景,观察isExistingTransaction返回值与handleExistingTransaction走哪个分支、newTransaction标记真假。


下一篇预告

第 27 篇:@Transactional的 7 大失效场景与源码归因——为什么你明明加了注解事务却不回滚?自调用、非 public、异常类型不对、多线程……逐一用源码定位。


如果这篇对你有帮助,欢迎点赞 · 收藏 · 关注三连支持。

Spring 源码系列共 30 篇,由浅入深持续更新中。有疑问或想深挖的源码点,评论区告诉我,下篇见。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询