Java 事务回滚详解:@Transactional 注解中 rollbackFor 和 rollbackOn 的区别与使用

在日常 Java 开发中,事务控制是保障数据一致性的关键手段。Spring 为我们提供了非常强大的声明式事务管理方式,通过简单地使用 @Transactional 注解,就可以实现事务控制。但是在使用过程中,很多人对事务的“回滚时机”理解并不清晰,尤其是 rollbackForrollbackOn 的使用。

本篇博客将全面解析这两个参数的意义、使用场景、以及常见误区。


一、什么是事务回滚?

事务回滚指的是:当执行过程中发生异常时,之前对数据库所做的更改全部撤销,数据库状态恢复到事务开始前的状态。这是数据库“原子性”原则的体现。


二、Spring 中的 @Transactional 默认行为

在 Spring 中,使用注解方式开启事务非常简单:

@Transactional
public void doSomething() {
    // 执行数据库操作
}

此时的默认行为是:

  • 事务会在方法成功执行后提交;
  • 遇到 RuntimeExceptionError,会自动回滚;
  • 遇到 Checked Exception(即编译时异常),不会自动回滚。

例如:

@Transactional
public void test1() {
    throw new RuntimeException(); // ✅ 会回滚
}

@Transactional
public void test2() throws Exception {
    throw new Exception(); // ❌ 不会回滚
}

三、使用 rollbackFor 让事务回滚受检异常

如果你希望事务在任何异常发生时都回滚,包括受检异常,比如 IOExceptionSQLException,就需要显式指定:

@Transactional(rollbackFor = Exception.class)
public void test3() throws Exception {
    throw new Exception(); // ✅ 会回滚
}
  • rollbackFor 的值可以是一个或多个异常类;
  • 你可以根据需要选择只对某些异常类型回滚,其他的则不回滚。

四、rollbackForrollbackOn 的区别

| 特性 | rollbackFor | rollbackOn |
| —– | ———————————————————- | ——————————— |
| 适用范围 | Spring | Java EE / JTA |
| 包名 | org.springframework.transaction.annotation.Transactional | javax.transaction.Transactional |
| 默认行为 | 回滚 RuntimeException | 不回滚任何异常 |
| 明确配置后 | 可回滚任何指定异常 | 可回滚任何指定异常 |

示例比较:

Spring 中的写法:

import org.springframework.transaction.annotation.Transactional;

@Transactional(rollbackFor = Exception.class)
public void springTransaction() throws Exception {
    throw new Exception("测试受检异常");
}

JTA(Java EE)中的写法:

import javax.transaction.Transactional;

@Transactional(rollbackOn = Exception.class)
public void jtaTransaction() throws Exception {
    throw new Exception("测试受检异常");
}

注意:使用的是不同的注解类,不能混用!


五、常见误区

❌ 误区1:以为所有异常都会触发事务回滚

Spring 默认只回滚 RuntimeException,不会回滚 Exception(受检异常)。这是导致事务未回滚的最常见原因。

❌ 误区2:以为 @Transactional 可以应用于任何方法

只有被 Spring 容器管理(即被 Spring 扫描并代理)的类中的 public 方法,@Transactional 才有效。如果你在 private 方法上加了注解,是不会生效的。

❌ 误区3:使用错误的注解类

Spring 和 JTA 的 @Transactional 注解来自不同的包,使用时务必导入正确:

  • Spring: org.springframework.transaction.annotation.Transactional
  • JTA: javax.transaction.Transactional

六、小结

常见问题与解决方式

| 问题 | 默认行为 | 解决方式 |
| ————- | —————————– | ——————————————————————————— |
| 事务不回滚受检异常 | ❌ 不回滚 | ✅ 添加 rollbackFor = Exception.class(Spring)或 rollbackOn = Exception.class(JTA) |
| 事务注解不生效 | ❌ 方法不是 public,类未被 Spring 管理 | ✅ 保证类被 Spring 扫描,方法为 public |
| 导入错误注解 | ❌ 使用了错误的 @Transactional 注解 | ✅ 使用正确包名下的注解(见下表) |

Spring 与 JTA 的 @Transactional 对比

| 特性 | Spring | JTA(Java EE) |
| —— | ———————————————————- | ——————————— |
| 注解类全名 | org.springframework.transaction.annotation.Transactional | javax.transaction.Transactional |
| 默认回滚行为 | 回滚 RuntimeException,不回滚 Exception | 不回滚任何异常 |
| 控制参数 | rollbackFor, noRollbackFor 等 | rollbackOn, dontRollbackOn |
| 常见场景 | Spring Boot, Spring MVC 项目 | Java EE, Jakarta EE 应用服务器项目 |
| 建议用法 | 用 Spring 的事务注解为主 | 仅在 Java EE 项目中使用 |


七、结语

事务控制是保障系统数据一致性的重要手段,理解事务的回滚机制尤为重要。在实际开发中,推荐明确指定异常回滚策略,避免因受检异常不回滚而造成数据异常。

希望这篇文章能帮你在开发中更精准地使用 @Transactional,写出更健壮、可控的代码。如果你有更多问题,欢迎留言讨论!