Spring 事务传播机制7 种行为详解一篇讲透面试官“Spring 事务的传播机制有哪些默认是什么”你“有 7 种最常用的是 REQUIRED默认有事务就加入没有就新建。还有 REQUIRES_NEW挂起当前新建事务、NESTED嵌套事务可回滚到保存点等。”面试官“REQUIRES_NEW 和 NESTED 有什么区别什么场景用”你“……”很多人能背出 7 个名字但一追问“挂起事务是什么意思”“嵌套事务如何实现回滚点”就卡壳了。本文从底层原理到业务场景彻底讲透 Spring 事务传播机制。一、什么是事务传播行为Spring 中事务传播行为指的是当一个事务方法被另一个事务方法调用时这个事务应该如何传播。通俗说方法 A 有事务方法 B 也有事务A 调用 BB 是在 A 的事务中执行还是另开一个新事务这就是传播行为决定的。二、7 种传播行为一览传播行为含义是否常用REQUIRED支持当前事务如果没有则新建✅ 最常用SUPPORTS支持当前事务如果没有则非事务执行一般MANDATORY支持当前事务如果没有则抛异常少见REQUIRES_NEW挂起当前事务新建事务执行✅ 常用NOT_SUPPORTED非事务执行挂起当前事务少见NEVER非事务执行如果有事务则抛异常极少NESTED在当前事务中创建嵌套事务有保存点✅ 常用Spring 默认传播行为REQUIRED。三、最常用的 3 种传播行为详解1. REQUIRED默认行为如果当前存在事务则加入该事务如果当前没有事务则新建一个事务。这是最常用的适合绝大多数业务场景。Transactional(propagationPropagation.REQUIRED)publicvoidmethodA(){// 执行数据库操作methodB();// 调用 methodB}Transactional(propagationPropagation.REQUIRED)publicvoidmethodB(){// 执行数据库操作}当methodA调用methodB时methodB直接加入methodA的事务。整个调用链共享同一个事务任何地方出现异常整个事务回滚。使用场景需要保证一系列操作原子性要么全部成功要么全部失败。2. REQUIRES_NEW行为挂起当前事务如果存在新建一个独立的事务执行新事务与当前事务无关互不影响。Transactional(propagationPropagation.REQUIRES_NEW)publicvoidmethodB(){// 这个操作会在独立的新事务中执行}如果methodAREQUIRED调用methodBREQUIRES_NEW则methodB会挂起methodA的事务新建一个事务。methodB提交或回滚后methodA的事务才恢复继续执行。两个事务相互独立methodB回滚不影响methodA反之亦然。使用场景记录操作日志即使业务失败日志也要保存发送通知消息不因主业务失败而影响通知异步任务独立的事务边界3. NESTED行为如果当前存在事务则在当前事务中创建一个嵌套事务利用数据库的保存点 savepoint如果当前没有事务则新建一个事务等同于 REQUIRED。Transactional(propagationPropagation.NESTED)publicvoidmethodB(){// 这个操作会在嵌套事务中执行}嵌套事务是外部事务的一部分但有自己的保存点。嵌套事务回滚时只回滚到保存点外部事务可以继续。外部事务回滚时所有嵌套事务也会回滚。与 REQUIRES_NEW 的区别对比REQUIRES_NEWNESTED事务独立性完全独立互不影响依赖外部事务外部回滚则内部也回滚回滚范围内部回滚不影响外部内部回滚可以只回滚到保存点不影响外部底层实现真正挂起事务新建连接/事务使用 JDBC 保存点savepoint数据库支持所有支持事务的数据库需要支持保存点如 PostgreSQL、Oracle、MySQL InnoDB使用场景批量处理中的部分失败希望失败的部分回滚但继续执行后续批次业务中的可回滚子流程四、其他传播行为了解即可SUPPORTS有事务则加入无事务则以非事务方式执行。适合不需要事务但能兼容事务的查询。MANDATORY必须已有事务否则抛IllegalTransactionStateException。适合强制要求调用方提供事务的场景。NOT_SUPPORTED以非事务方式执行如果当前有事务则挂起。适合不需要事务且不希望影响当前事务的操作。NEVER必须以非事务方式执行如果有事务则抛异常。五、事务传播的工作原理底层机制Spring 事务管理基于AOP 代理。当调用带Transactional的方法时代理会检查方法的事务属性传播行为、隔离级别等然后根据传播行为决定是否需要挂起当前事务是否需要新建事务是否加入当前事务是否创建保存点关键组件PlatformTransactionManager事务管理器如DataSourceTransactionManagerTransactionDefinition定义传播行为、隔离级别等TransactionStatus代表当前事务状态可保存点回滚REQUIRES_NEW 的挂起与恢复当方法标记为REQUIRES_NEW时Spring 会保存当前事务的状态连接、隔离级别等将当前事务挂起解绑资源创建新的事务连接并开始事务新事务完成后提交/回滚恢复原事务继续执行NESTED 的保存点如果数据库支持保存点JDBC 3.0Spring 会在进入嵌套事务时创建保存点。当嵌套事务回滚时回滚到该保存点外部事务可继续。六、代码示例实际效果演示ServicepublicclassOrderService{AutowiredprivatePaymentServicepaymentService;Transactional(propagationPropagation.REQUIRED)publicvoidcreateOrder(){// 保存订单orderDao.insert(order);try{paymentService.deductMoney();// REQUIRES_NEW}catch(Exceptione){// 扣款失败订单继续创建还是回滚// 取决于传播行为}// 继续其他操作}}ServicepublicclassPaymentService{Transactional(propagationPropagation.REQUIRES_NEW)publicvoiddeductMoney(){// 扣款操作// 如果这里抛出异常只回滚扣款不影响订单}}如果deductMoney是REQUIRES_NEW则扣款失败不会导致订单回滚订单依然创建成功。如果deductMoney是NESTED则扣款失败可回滚到保存点但外部事务可选择提交或继续回滚。七、常见面试追问Q1REQUIRES_NEW 和 NESTED 在代码上怎么区分REQUIRES_NEW完全独立事务内部异常不影响外部外部异常不影响内部。NESTED内部回滚不影响外部回滚到保存点但外部回滚会导致内部也回滚。Q2REQUIRES_NEW 会消耗数据库连接吗会。因为需要挂起当前事务的连接再获取一个新的连接。如果并发量高可能导致连接池耗尽。慎用。Q3Propagation.NESTED 在什么情况下不可用数据库不支持保存点如 MySQL 5.0 之前的 MyISAM 引擎事务管理器不支持嵌套事务如全局 JTA 事务Spring 默认的DataSourceTransactionManager支持但需要 JDBC 3.0 及以上。Q4同一个类中方法 AREQUIRED调用方法 BREQUIRES_NEW能生效吗不能。因为 AOP 代理只在外部调用时生效类内部直接调用不会经过代理所以传播行为会失效。解决方法将方法 B 放到另一个 Service 中通过AopContext.currentProxy()调用使用Autowired注入自身代理Q5传播行为与事务隔离级别的关系两者独立配置。传播行为决定事务边界隔离级别决定并发数据可见性。例如REQUIRES_NEW可以配置ISOLATION_READ_COMMITTED。八、最佳实践建议默认使用 REQUIRED除非有明确的独立事务需求。记录日志、发消息使用REQUIRES_NEW避免影响主业务。批量处理中部分失败需回滚单项使用NESTED前提是数据库支持保存点。避免过度使用 REQUIRES_NEW会增加连接占用和锁争用。自调用失效问题确保事务方法被 Spring 代理调用推荐将事务方法放在单独 Bean 中。九、总结表传播行为外部无事务外部有事务典型场景REQUIRED新建事务加入事务大多数业务SUPPORTS非事务加入事务兼容查询MANDATORY抛异常加入事务强制需要事务REQUIRES_NEW新建事务挂起外部新建事务日志、消息NOT_SUPPORTED非事务挂起外部耗时非事务操作NEVER非事务抛异常禁止事务NESTED新建事务创建保存点批量子回滚一句话记住传播机制REQUIRED 是老大REQUIRES_NEW 另起炉灶NESTED 嵌套留一手。希望这篇文章能帮你彻底掌握 Spring 事务传播机制从容应对面试和实际开发欢迎继续讨论。