Spring事务回滚关键在于异常必须穿透代理边界:需确保异常未被吞、类型匹配(默认仅RuntimeException/Error回滚)、调用路径经代理且方法为public,否则事务不回滚。

关键在于让异常真实穿透事务代理边界,并被 Spring 识别为回滚信号。不是“抛了就行”,而是要确保它不被拦截、类型被支持、调用路径有效。
异常必须穿透@Transactional方法边界
Spring 的事务回滚依赖未被捕获的异常向上冒泡至代理层。一旦在事务方法内用 try-catch 吞掉异常且未 re-throw,事务就视为成功提交。
- ❌ 错误:只记录日志,不抛出
- ✅ 正确:catch 后必须 throw e 或包装后抛出(如 throw new RuntimeException("业务失败", e))
- 若需区分处理逻辑,可在 catch 中做补偿操作,但最终仍要抛出可触发回滚的异常
确认异常类型匹配回滚策略
Spring 默认仅对 RuntimeException 及其子类 和 Error 自动回滚。抛出 Exception(如 IOException、SQLException)不会触发回滚,除非显式配置。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 默认生效:IllegalArgumentException、NullPointerException、IllegalStateException 等运行时异常
- 检查异常需声明:@Transactional(rollbackFor = SQLException.class)
- 避免滥用
rollbackFor = Exception.class,应按业务语义精准指定需回滚的异常类型
保证事务代理真正生效
@Transactional 是基于 Spring AOP 代理实现的,只有通过代理对象调用 public 方法,事务才起作用。
立即学习“Java免费学习笔记(深入)”;
- ❌ 失效场景:本类中用 this.methodB() 调用另一个事务方法
- ❌ 方法为 private / final / protected —— 代理无法增强
- ❌ 手动 new 对象或 @Async 异步方法 —— 脱离事务上下文
- ✅ 解决:通过注入的 Bean 引用调用,或改用 TransactionTemplate 编程式事务
验证回滚是否真实发生
不能只看控制台有没有报错,要从数据和日志两个层面确认。
- 在方法末尾主动抛 RuntimeException("test"),观察数据库变更是否消失
- 开启日志:logging.level.org.springframework.transaction=DEBUG,搜索 "Initiating transaction rollback"
- 查 SQL 日志是否出现 ROLLBACK,并确认数据库引擎支持事务(如 MySQL 的 InnoDB)

















