Java事务回滚详解以及常见误区
一、什么是事务回滚?
事务回滚指的是:当执行过程中发生异常时,之前对数据库所做的更改全部撤销,数据库状态恢复到事务开始前的状态。这是数据库“原子性”原则的体现。
二、Spring 中的@Transactional默认行为
在 Spring 中,使用注解方式开启事务非常简单:
@Transactional
public void doSomething() {
// 执行数据库操作
}
此时的默认行为是:
- 事务会在方法成功执行后提交;
- 遇到 RuntimeException 或 Error,会自动回滚;
- 遇到 Checked Exception(即编译时异常),不会自动回滚。
例如:
@Transactional
public void test1() {
throw new RuntimeException(); // ✅ 会回滚
}
@Transactional
public void test2() throws Exception {
throw new Exception(); // ❌ 不会回滚
}
三、使用rollbackFor让事务回滚受检异常
如果你希望事务在任何异常发生时都回滚,包括受检异常,比如 IOException、SQLException,就需要显式指定:
@Transactional(rollbackFor = Exception.class)
public void test3() throws Exception {
throw new Exception(); // ✅ 会回滚
}
rollbackFor的值可以是一个或多个异常类;- 你可以根据需要选择只对某些异常类型回滚,其他的则不回滚。
四、rollbackFor和rollbackOn的区别
| 特性 | 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,写出更健壮、可控的代码。
附:下面说说我经常见到的3种事务不回滚的产生原因:
(1)声明式事务配置切入点表达式写错了,没切中Service中的方法
(2)Service方法中,把异常给try catch了,但catch里面只是打印了异常信息,没有手动抛出RuntimeException异常
(3)Service方法中,抛出的异常不属于运行时异常(如IO异常),因为Spring默认情况下是捕获到运行时异常就回滚
到此这篇关于Java事务回滚详解以及常见误区的文章就介绍到这了,更多相关Java事务回滚内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot读取resource目录下文件失败的原因及解决方案
在idea中运行时,有些resource下文件读取工具类能够正常获取读取到文件,但是通过java–jar的方式去运行jar包,此时resource下文件读取工具类读取文件就失效了,本文就给大家介绍一下SpringBoot读取resource目录下文件失败解决方案,需要的朋友可以参考下2023-08-08
JAVA CountDownLatch与thread-join()的区别解析
这篇文章主要介绍了JAVA CountDownLatch与thread-join()的区别解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2019-08-08
Spring源码BeanFactoryPostProcessor详解
BeanFactoryPostProcessor的执行时机是在Spring扫描完成后,Bean初始化前,当我们实现BeanFactoryPostProcessor接口,可以在Bean的初始化之前对Bean进行属性的修改,下面通过本文看下Spring源码分析-BeanFactoryPostProcessor的实例代码,感兴趣的朋友一起看看吧2021-11-11


最新评论