Spring默认仅对RuntimeException及其子类和Error自动回滚,对IOException等检查异常不回滚,需通过rollbackFor显式指定;事务生效还需满足方法为public、避免同类调用、数据库支持事务且异常不被静默捕获。

Java 中通过异常触发事务回滚,是保障业务数据一致性的核心手段。关键不在于“抛异常”本身,而在于异常如何被事务管理器识别、捕获,并驱动数据库撤销已执行操作。实际落地需结合框架机制、异常类型和调用方式综合设计。
Spring 默认只对运行时异常自动回滚
Spring 的 @Transactional 注解默认仅在抛出 RuntimeException 及其子类(如 IllegalArgumentException、NullPointerException、IllegalStateException)时触发回滚。这是最常用也最安全的配置方式。
- 业务校验失败(如金额为负、库存不足)应主动抛出运行时异常,例如
throw new IllegalArgumentException("订单金额不能为零") - 数据库主键冲突、唯一索引违例等会由 JDBC 抛出
SQLIntegrityConstraintViolationException(继承自RuntimeException),天然触发回滚 - 若方法内用
try-catch吞掉运行时异常且未重新抛出,事务将无法感知失败,导致“假成功”
检查异常需显式声明才回滚
IOException、SQLException 等检查异常(checked exception)默认不会导致 Spring 回滚。若业务逻辑中必须抛出这类异常且希望事务失效,必须在注解中明确指定:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 写法:
@Transactional(rollbackFor = SQLException.class)或@Transactional(rollbackFor = Exception.class) - 典型场景:文件解析服务中读取 Excel 失败(
IOException)、调用外部 HTTP 接口超时后需撤回本地入库操作 - 注意:
rollbackFor指定的是“向上匹配的异常类型”,不是必须精确等于抛出的异常类
确保事务能真正生效的四个前提
即使加了 @Transactional,以下情况会导致事务失效,回滚机制形同虚设:
立即学习“Java免费学习笔记(深入)”;
- 方法必须是 public 的——private/protected 方法加注解无效
- 不能在同一个类中直接调用带事务的方法(即“同类调用”),否则绕过 Spring 代理,事务不生效
- 数据库连接必须支持事务(如 MySQL 的 InnoDB 引擎),MyISAM 不支持事务回滚
- 事务方法内不能手动捕获异常后静默处理(如
catch (Exception e) { log.error(...); }),必须让异常穿透出去或显式调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
分布式或多数据源场景需补偿而非强回滚
单体应用可用本地事务兜底,但微服务间跨库、跨服务的操作无法依赖数据库级回滚。此时应转向最终一致性方案:
- 使用 Saga 模式:把转账拆成“扣款→发消息→充值→确认”,每步失败则执行反向操作(退款)
- 引入 事务消息(如 RocketMQ 事务消息):先发“半消息”,本地事务成功后再提交,失败则回查并回滚
- 所有关键步骤必须具备 幂等性 和 可补偿性,比如用唯一业务 ID 防重,用状态机记录执行进度

















