Spring @Transactional 默认仅对 RuntimeException 及其子类、Error 自动回滚;IOException 等受检异常不回滚,需通过 rollbackFor 显式指定,且要求异常未被捕获、方法为 public、经 Spring 代理调用、传播行为支持事务。

Java中@Transactional默认只对RuntimeException及其子类(即非受检异常)自动回滚,这是Spring事务管理的默认行为,无需额外配置。
哪些异常会触发自动回滚
Spring事务默认将以下异常视为“回滚异常”:
-
RuntimeException及其所有子类(如NullPointerException、IllegalArgumentException、自定义RuntimeException) -
Error及其子类(如OutOfMemoryError)
而Exception的其他子类(即受检异常,如IOException、SQLException)默认不会触发回滚,除非显式声明。
确保非受检异常触发回滚的关键点
即使抛出的是RuntimeException,仍需满足几个前提条件才能成功回滚:
- 方法必须被@Transactional正确代理:该注解仅在public方法上生效,且调用必须经过Spring代理(即不能在同一个类中直接调用,否则AOP失效)
-
事务传播行为需支持事务:例如
PROPAGATION_REQUIRED(默认),避免使用PROPAGATION_SUPPORTS或PROPAGATION_NEVER -
数据源和事务管理器已正确配置:如
DataSourceTransactionManager或JpaTransactionManager已声明并启用 - 异常未被吞掉:try-catch后未重新抛出,或捕获后抛出新的非受检异常
常见失效场景与修复示例
以下情况看似抛了RuntimeException,但事务却不回滚:
-
同一类内自调用:A方法加了
@Transactional,内部调用本类B方法(也抛异常),此时B不走代理,事务不生效 → 改为通过注入自身Bean调用,或拆到不同Service -
catch后静默处理:
try { ... } catch (Exception e) { log.error(...); }→ 需改为throw new RuntimeException(e)或直接让异常向上抛 -
方法不是public:private/protected方法上的
@Transactional会被忽略 → 改为public,并确保是代理对象调用
如需对受检异常也回滚,可显式指定
若业务逻辑中明确抛出如MyBusinessException extends Exception,又希望它触发回滚,只需:
@Transactional(rollbackFor = MyBusinessException.class)
也可指定多个:rollbackFor = {MyBusinessException.class, IOException.class}
注意:noRollbackFor可用来排除某些非受检异常(如特定RuntimeException不希望回滚)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











