Spring事务默认仅对RuntimeException及其子类、Error自动回滚,受检异常不回滚;需通过rollbackFor显式配置,且catch后必须重抛或调用setRollbackOnly()才能确保回滚。

在 Spring 的声明式事务中,默认只对 RuntimeException 及其子类、Error 进行自动回滚,而对受检异常(如 Exception 及其非 RuntimeException 子类)不会回滚。若想让事务在捕获特定异常时回滚,需显式配置,并结合 try-catch 精准处理逻辑——关键在于:**捕获 ≠ 阻止回滚,回滚控制权在事务管理器,不在 catch 本身**。
明确哪些异常会触发回滚
Spring 默认回滚策略基于异常类型,而非是否被 catch。即使你用 try-catch 捕获了 RuntimeException,只要没手动提交或吞掉异常,事务仍会按规则回滚。但如果你在 catch 中“吃掉”异常(不重新抛出、也不声明 rollback),事务就认为操作成功,不会回滚。
- 默认自动回滚:RuntimeException、Error 及其所有子类(如 NullPointerException、IllegalArgumentException、OutOfMemoryError)
- 默认不回滚:Exception 及其非运行时子类(如 IOException、SQLException、CustomCheckedException)
- 可通过 @Transactional(rollbackFor = {CustomException.class}) 显式指定回滚的异常类型
在 catch 中处理特定异常并主动控制回滚
当需要捕获某个异常(如业务校验失败的 CustomBizException)、记录日志、返回友好提示,同时确保事务回滚,正确做法是:捕获后重新抛出,或抛出一个被配置为回滚的异常。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- ✅ 正确示例(捕获后重抛运行时异常):
@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
try {
accountDao.withdraw(fromId, amount);
accountDao.deposit(toId, amount);
} catch (InsufficientBalanceException e) {
log.warn("余额不足,转账失败", e);
throw new RuntimeException("转账失败:余额不足", e); // 触发回滚
}
}
- ✅ 更规范做法:用 @Transactional(rollbackFor = InsufficientBalanceException.class),然后直接 throw 原异常
- ❌ 错误做法:catch 后仅 log + return,事务将提交(因无异常上抛)
避免在事务方法内“静默吞异常”
常见误区是以为“我 catch 了,所以事务该回滚”,其实 Spring 事务切面只看方法退出时是否有未捕获的、匹配 rollbackFor 的异常。一旦你在方法内把异常 catch 住又不抛出,事务上下文就收不到回滚信号。
立即学习“Java免费学习笔记(深入)”;
- 如果必须局部处理异常(如补偿某些状态),可考虑:将事务边界前移(拆分方法)、使用 TransactionTemplate 编程式回滚、或在 catch 中显式调用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
- 例如:
@Transactional
public void doWithFallback() {
try {
riskyOperation();
} catch (SpecificException e) {
log.error("主操作失败,执行降级", e);
fallbackOperation();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); // 强制回滚
}
}
推荐实践:自定义异常 + 精确 rollbackFor
为语义清晰和统一管理,建议定义自己的运行时业务异常(继承 RuntimeException),或在 @Transactional 中精准声明 rollbackFor,避免全局修改默认行为。
- 定义:public class BizValidationException extends RuntimeException
- 使用:@Transactional(rollbackFor = BizValidationException.class)
- 抛出:throw new BizValidationException("用户名已存在")
- 这样既可被事务识别回滚,又便于全局异常处理器(@ControllerAdvice)统一捕获响应

















