基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

在 Spring 事务中,如果抛出普通的 Exception(非 RuntimeException),事务默认会回滚吗?

知识点图片

默认情况下,不会回滚

在 Spring 事务(@Transactional)中,默认的回滚机制如下:

  1. 会触发回滚的异常

    • Unchecked Exception(非受检异常):即 RuntimeException 及其所有子类(如 NullPointerException, IllegalArgumentException 等)。
    • Error:如 OutOfMemoryError 等系统级错误。
  2. 不会触发回滚的异常

    • Checked Exception(受检异常/普通 Exception):即直接继承自 Exception 但不是 RuntimeException 的异常(如 IOException, SQLException, ClassNotFoundException 等)。如果抛出了这类异常,Spring 默认会提交事务,而不是回滚。

为什么 Spring 默认这样设计?

Spring 的这一设计理念源自 EJB(Enterprise JavaBeans)规范和 Java 的异常设计哲学:

  • Checked Exception:被认为是“可预见的、可恢复的”业务级异常,程序应当捕获并采取补偿措施,所以不强制回滚事务。
  • RuntimeException / Error:被认为是“不可恢复的、非预期的”程序 BUG 或系统故障,因此必须回滚以保证数据一致性。

如何让普通的 Exception 也触发回滚?

在实际的业务开发中,我们通常希望只要发生任何异常,都直接回滚事务。为了改变默认行为,你需要使用 @Transactional 注解的 rollbackFor 属性:

java
// 显式指定 rollbackFor 为 Exception.class
// 这样无论是 RuntimeException 还是普通的 Exception 都会触发事务回滚
@Transactional(rollbackFor = Exception.class)
public void myServiceMethod() throws Exception {
    // 数据库操作 1
    
    // 抛出普通的受检异常,事务将会回滚
    throw new Exception("发生了一个普通异常"); 
    
    // 数据库操作 2
}

最佳实践
在绝大多数现代项目的日常开发中,强烈建议在类或方法上统一加上 @Transactional(rollbackFor = Exception.class),以避免因为抛出 Checked Exception 而导致的数据不一致问题(比如常见的由于 SQLException 没有回滚导致产生了脏数据)。

00:00
00:00