
前提Spring 事务底层依靠AOP 动态代理只有代理对象调用方法才会触发事务增强同时事务生效需要满足数据库引擎支持事务InnoDBMyISAM 不支持。注解Transactional1. 方法不是 public最常见Spring AOP 只拦截public方法private/protected/default方法加注解完全无效。Service public class UserService { // ❌ private事务失效 Transactional private void addUser() { userMapper.insert(...); int i 1/0; // 抛异常不会回滚 } }2. 同类内部方法调用this 调用不走代理在同一个类中直接this.xxx()调用带Transactional的方法不是代理对象调用AOP 不会切入。Service public class UserService { public void test() { // ❌ this调用不是代理对象addUser事务失效 this.addUser(); } Transactional public void addUser() { userMapper.insert(...); int i 1/0; // 异常不回滚 } }✅ 解决方案自身注入UserService self;self.addUser()。3. 异常类型不对捕获了异常 / 抛出非回滚异常Transactional默认只对RuntimeException 和 Error触发回滚受检异常Exception默认不回滚。场景 3.1 自己 try-catch 吃掉异常Transactional public void addUser() { try { userMapper.insert(...); int i 1/0; } catch (Exception e) { // ❌ 异常被捕获没有抛出给AOP事务不会回滚 log.error(error, e); } }场景 3.2 抛出受检异常没指定 rollbackForTransactional public void addUser() throws IOException { userMapper.insert(...); throw new IOException(IO异常); // ❌ IOException是受检异常默认不回滚 }✅ 修复Transactional(rollbackFor Exception.class)4. 传播行为配置错误典型REQUIRES_NEW独立事务SUPPORTS非事务环境下就是无事务NOT_SUPPORTED 强制以非事务运行。// ❌ NOT_SUPPORTED不开启事务发生异常不会回滚 Transactional(propagation Propagation.NOT_SUPPORTED) public void addUser(){ userMapper.insert(...); int i1/0; }5. 数据库底层不支持事务MyISAM 引擎不支持事务哪怕代码写对Transactional也无法回滚。查看表引擎show create table user;✅ 必须使用 InnoDB。6. 多线程场景事务失效事务绑定在当前线程新开子线程执行数据库操作子线程是全新事务上下文和主线程事务隔离。Transactional public void test() { userMapper.insertA(); new Thread(() - { userMapper.insertB(); int i1/0; // ❌ 子线程异常不会回滚insertA }).start(); }7. 事务超时时间超时自动回滚不是不生效是触发回滚// 5秒超时超时后自动回滚 Transactional(timeout 5) public void test() throws InterruptedException { userMapper.insert(); Thread.sleep(6000); }8. 注解被错误放在接口上老版本 SpringSpring AOP 优先读取实现类上的注解只在接口上加Transactional使用 CGLIB 代理时事务会失效。最佳实践Transactional写在Service 实现类的 public 方法。9. 嵌套事务传播 NESTED外层捕获异常导致内层不回滚Service public class UserService { Autowired private OrderService orderService; Transactional public void main() { userMapper.insertUser(); try { // NESTED 嵌套事务 orderService.addOrder(); } catch (Exception e) { log.error(子事务异常); // ❌ 外层捕获异常外层事务不回滚内层子事务回滚 } } } Service class OrderService{ Transactional(propagation Propagation.NESTED) public void addOrder(){ orderMapper.insert(); int i1/0; } }总结AOP 代理问题非 public、同类 this 调用异常问题吞异常、rollbackFor 没配置数据库MyISAM 引擎传播属性NOT_SUPPORTED/SUPPORTS 误用线程跨线程事务隔离注解位置仅接口上加注解CGLIB扩展Q为什么同类 this 调用事务失效ASpring 事务由 AOP 代理对象增强this 是原始对象没有经过代理不会执行事务拦截器。QrollbackForException.class 作用A默认只回滚 RuntimeException/Error加上之后所有 Exception包含受检异常都会触发回滚。Spring 事务传播行为Propagation核心多个事务方法相互调用时事务如何传递一共 7 种传播类型含义场景说明REQUIRED默认如果当前存在事务就加入该事务没有则新建一个事务绝大多数业务同一件事要么全部成功要么全部回滚REQUIRES_NEW新建独立事务如果当前有事务挂起原有事务执行新事务互不影响日志记录、独立审计子事务失败不影响外层事务SUPPORTS当前有事务就加入没有事务就以非事务方式执行查询场景可有可无事务MANDATORY必须运行在已有事务中当前无事务直接抛异常强制外层必须开启事务防止单独调用NOT_SUPPORTED以非事务方式执行当前有事务就挂起原有事务大批量查询不想占用事务资源NEVER强制非事务运行如果当前存在事务直接抛异常禁止事务环境只读统计NESTED嵌套事务有事务则嵌套在当前事务内保存点 savepoint无事务新建事务子事务回滚不会导致外层事务回滚外层事务回滚嵌套子事务一定回滚重点区分REQUIRES_NEW vs NESTEDREQUIRES_NEW两个完全独立事务外层事务挂起。子事务提交后不受外层影响子事务异常外层可以捕获继续提交。NESTED同一个物理事务基于保存点 savepoint。只有外层事务提交嵌套事务才真正提交外层回滚嵌套一定回滚。NESTED 不是独立事务是保存点REQUIRES_NEW 是全新独立事务。扩展传播行为默认值REQUIREDREQUIRES_NEW 挂起事务原理Spring 事务管理器暂停当前事务保存上下文执行完恢复哪些传播行为会创建新事务REQUIRED、REQUIRES_NEW、NESTEDSpring 7 种事务传播行为 代码演示 回滚规则前提AOP 代理调用才生效同类方法内部调用事务失效。Transactional默认只对RuntimeException / Error触发回滚受检异常默认不回滚。外层方法叫内层方法外层 调用方内层 被调用方。公共基础代码两个 Service方便测试Service public class OuterService { Autowired private InnerService innerService; // 外层方法 public void outer(){} } Service public class InnerService { // 内层方法 public void inner(){} }1. REQUIRED默认有事务就加入当前事务无事务新建事务。外层内层是同一个事务Service public class OuterService { Autowired private InnerService innerService; Transactional(propagation Propagation.REQUIRED) public void outer() { // 插入订单 innerService.inner(); // 外层抛异常 throw new RuntimeException(外层异常); } } Service public class InnerService { Transactional(propagation Propagation.REQUIRED) public void inner() { // 扣库存 } }✅ 回滚规则外层抛异常 →整个事务回滚内层操作回滚内层抛异常外层不捕获 →整个事务回滚内层抛异常外层 try-catch 接住依然会回滚异常标记了事务为 rollback-only外层 catch 后提交时报异常。场景正常业务增删改同业务要么全成要么全回。2. REQUIRES_NEW如果外层有事务挂起外层事务新建独立事务。两个完全独立物理事务互不干扰。Service public class OuterService { Autowired private InnerService innerService; Transactional public void outer() { // 插入订单 try { innerService.inner(); } catch (Exception e) { // 捕获内层异常外层继续跑 } // 外层正常结束外层事务提交 } } Service public class InnerService { Transactional(propagation Propagation.REQUIRES_NEW) public void inner() { // 扣库存 throw new RuntimeException(内层异常); } }✅ 回滚规则内层抛异常 →内层事务回滚外层事务不受影响可以正常提交try-catch 捕获内层异常外层抛异常 →外层事务回滚内层事务已经独立提交完成不会回滚重点内层事务执行完就提交外层事务被挂起两者独立。 适用操作日志、审计记录就算主业务失败日志也要入库。3. SUPPORTS当前有事务就加入事务没有事务就非事务方式运行Service public class OuterService { Autowired private InnerService innerService; Transactional public void outer() { // 外层存在事务 innerService.inner(); } } Service public class InnerService { Transactional(propagation Propagation.SUPPORTS) public void inner() { // 查询或者更新 } }✅ 回滚规则外层有事务内层加入外层事务任意地方异常整体回滚和 REQUIRED 行为一致外层没有事务内层无事务发生异常不会回滚已经执行的 SQL 持久化适用查询方法有事务环境就参与事务没有就普通查询。4. MANDATORY必须运行在已有事务中外层没有事务直接抛异常不会新建事务Service public class OuterService { Autowired private InnerService innerService; // 外层不加 Transactional public void outer() { innerService.inner(); // ❌ 直接抛出 IllegalTransactionStateException } } Service public class InnerService { Transactional(propagation Propagation.MANDATORY) public void inner() { } }✅ 回滚规则外层存在事务内层加入外层事务统一回滚外层无事务直接报错方法不执行。适用强制该方法必须被事务方法调用防止单独调用造成数据不一致。5. NOT_SUPPORTED以非事务方式执行外层有事务就挂起外层事务内层不在事务里挂起suspend ≠ 提交 / 回滚外层事务只是临时把外层事务暂停、放到一边保存起来然后执行当前这个无事务的方法等内层方法执行完毕之后再恢复外层事务继续跑。概括外层事务先暂停内层裸跑没有事务内层跑完再把外层事务捡回来继续执行。Service public class OuterService { Autowired private InnerService innerService; Transactional public void outer() { // 外层事务开启调用内层时外层事务被挂起 innerService.inner(); // 内层执行完恢复外层事务 } } Service public class InnerService { Transactional(propagation Propagation.NOT_SUPPORTED) public void inner() { // 内层无事务这里抛异常内层SQL不会回滚 throw new RuntimeException(); } }✅ 回滚规则内层代码抛异常内层操作不会回滚无事务外层捕获异常后外层事务继续提交外层没捕获外层事务回滚。适用大批量查询大报表不想占用事务连接。6. NEVER禁止在事务中执行外层存在事务直接抛异常必须非事务环境Service public class OuterService { Autowired private InnerService innerService; Transactional public void outer() { innerService.inner(); // ❌ 抛出 IllegalTransactionStateException } } Service public class InnerService { Transactional(propagation Propagation.NEVER) public void inner() { } }✅ 回滚规则外层有事务直接报错外层无事务普通非事务执行异常不会回滚。适用统计任务明确禁止事务环境。7. NESTED 嵌套事务外层有事务基于 JDBC Savepoint 保存点嵌套在同一个物理事务外层无事务新建事务。 ⚠️ 和 REQUIRES_NEW 最大区别同一个物理事务不是独立事务Service public class OuterService { Autowired private InnerService innerService; Transactional public void outer() { // 外层事务开启创建savepoint try { innerService.inner(); } catch (Exception e) { // 捕获内层异常只回滚到savepoint外层事务还能继续提交 System.out.println(内层异常但是外层可以提交); } // 外层正常执行最终提交 } } Service public class InnerService { Transactional(propagation Propagation.NESTED) public void inner() { throw new RuntimeException(内层嵌套异常); } }✅ 回滚规则内层抛异常外层 try-catch 捕获只回滚内层操作外层事务可以正常提交 ✅外层抛异常无论内层是否成功外层整体回滚内层 savepoint 一起回滚底层JDBC Savepoint不是独立事务。MySQL InnoDB 支持。适用主流程不能回滚但子步骤失败可以单独撤销子步骤。 核心对比总结表传播行为外层有事务外层无事务独立事务内层异常 (外层 catch)外层异常REQUIRED加入外层事务新建事务否标记 rollback-only整体回滚整体回滚REQUIRES_NEW挂起外层新建独立事务新建事务是内层回滚外层可提交外层回滚内层已提交不受影响SUPPORTS加入外层事务非事务执行否整体回滚整体回滚MANDATORY加入外层事务抛异常否整体回滚整体回滚NOT_SUPPORTED挂起外层内层非事务非事务执行否内层不回滚外层回滚内层已持久化NEVER抛异常非事务执行否无机会执行无机会执行NESTED创建 savepoint 嵌套新建事务否仅回滚 savepoint外层可提交外层整体回滚