: 事务传播行为源码)
阅读前提示第 25 篇看到TransactionInterceptor在业务方法前后管理事务。本篇深入事务最核心、也最容易考糊的概念——传播行为Propagation。当你在一个事务方法里调用另一个事务方法Spring 怎么决定「新建事务」还是「加入已有事务」答案在AbstractPlatformTransactionManager.getTransaction。一、引子为什么需要传播行为现实中常出现「外层方法开事务内层方法也标了 Transactional」的场景。内层是复用外层事务、自己新开一个还是干脆不事务这就是传播行为要回答的。Transactional(propagationPropagation.REQUIRED)// 默认publicvoidouter(){inner();}Transactional(propagationPropagation.REQUIRES_NEW)publicvoidinner(){/* ... */}二、七种传播行为一览行为含义REQUIRED默认有就加入没有就新建REQUIRES_NEW挂起当前事务新建一个独立事务NESTED在当前事务内开嵌套保存点仅 JDBC 支持SUPPORTS有事务就加入没有就以非事务执行NOT_SUPPORTED挂起当前事务以非事务执行NEVER必须在非事务环境否则抛异常MANDATORY必须已有事务否则抛异常三、源码追踪getTransaction 的决策// AbstractPlatformTransactionManager.javaOverridepublicfinalTransactionStatusgetTransaction(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){// 挂起外层 → 新建事务SuspendedResourcesHoldersuspendedResourcessuspend(null);returnstartTransaction(definition,transaction,debugEnabled,suspendedResources);}else{// SUPPORTS / NOT_SUPPORTED / NEVER → 非事务执行returnprepareTransactionStatus(definition,null,true,newSynchronization,debugEnabled,null);}}3.1 已有事务时的关键分支privateTransactionStatushandleExistingTransaction(TransactionDefinitiondefinition,Objecttransaction,booleandebugEnabled){intpropagationdefinition.getPropagationBehavior();if(propagationPROPAGATION_NEVER){thrownewIllegalTransactionStateException(已存在事务NEVER 不允许);}if(propagationPROPAGATION_NOT_SUPPORTED){Objectsuspendedsuspend(transaction);// 挂起现有事务returnprepareTransactionStatus(...非事务...);}if(propagationPROPAGATION_REQUIRES_NEW){Objectsuspendedsuspend(transaction);// ★ 挂起外层returnstartTransaction(definition,transaction,debugEnabled,suspended);// ★ 全新事务}if(propagationPROPAGATION_NESTED){if(useSavepointForNestedTransaction()){DefaultTransactionStatusstatusprepareTransactionStatus(...);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/NESTEDREQUIRES_NEW 不会传播行为在提交时判定不在getTransaction进入时就已决策 面试题自测七种传播行为中哪些会新建事务、哪些加入、哪些非事务REQUIRED与REQUIRES_NEW的本质区别NESTED的保存点机制是什么有何限制getTransaction如何判断「已有事务」MANDATORY和NEVER分别在什么情况下抛异常内层REQUIRES_NEW异常外层REQUIRED会回滚吗 Debug 小技巧在AbstractPlatformTransactionManager.getTransaction断点分别用REQUIRED调REQUIRED、REQUIRED调REQUIRES_NEW两种场景观察isExistingTransaction返回值与handleExistingTransaction走哪个分支、newTransaction标记真假。下一篇预告第 27 篇Transactional的 7 大失效场景与源码归因——为什么你明明加了注解事务却不回滚自调用、非 public、异常类型不对、多线程……逐一用源码定位。如果这篇对你有帮助欢迎点赞 · 收藏 · 关注三连支持。Spring 源码系列共 30 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。