Java事务回滚默认仅响应RuntimeException和Error;受检异常需显式配置rollbackFor,且须避免非public方法、自调用、异常被捕获不抛出等导致事务失效的陷阱。

Java 中事务回滚的关键在于:**让 Spring 捕获到未处理的运行时异常(RuntimeException)或 Error,默认才会触发回滚**;受检异常(Exception 及其子类,如 IOException、SQLException)默认不回滚,需显式配置。
默认回滚规则:只对 RuntimeException 和 Error 生效
Spring 的声明式事务(@Transactional)默认采用 rollbackFor = RuntimeException.class 策略。这意味着:
- 方法中抛出 NullPointerException、IllegalArgumentException、ServiceException(若继承 RuntimeException)等 → 自动回滚
- 方法中抛出 IOException、SQLException、Exception 等受检异常 → 事务不回滚,提交成功
- 即使 catch 住异常但没重新抛出,或抛出后又吞掉(empty catch),事务也会正常提交
显式指定回滚异常类型
若业务逻辑中明确要对某类受检异常也回滚,需在 @Transactional 中配置 rollbackFor:
@Transactional(rollbackFor = {IOException.class, SQLException.class})
也可用更宽泛的写法:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
@Transactional(rollbackFor = Exception.class)
⚠️ 注意:不要写成 rollbackFor = Throwable.class —— 因为 Throwable 包含 Error(如 OutOfMemoryError),而 Spring 默认已对 Error 回滚,重复指定无害但不必要,且可能掩盖设计问题。
避免事务不生效的常见陷阱
以下情况会导致 @Transactional 失效,异常发生时事务也不回滚:
- 方法不是 public:@Transactional 仅对 public 方法生效(基于代理机制)
- 自调用失效:同一个类中,A 方法调用本类的 B 方法(B 有 @Transactional),B 的事务注解不生效(代理对象未介入)
- 异常被内部 catch 并“吃掉”:没有 re-throw 或抛出新异常,事务视为正常结束
- 使用了错误的传播行为:如 propagation = NOT_SUPPORTED,当前方法不加入事务,自然谈不上回滚
主动控制回滚:setRollbackOnly()
在编程式事务或需要动态判断是否回滚时,可通过 TransactionStatus 强制标记回滚:
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行数据库操作
if (someCondition) {
status.setRollbackOnly(); // 明确标记为仅回滚
}
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
在声明式事务中,也可以通过 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 实现类似效果(慎用,应优先用异常驱动)。

















