spring中事务为什么会回滚?什么原理?

发布于:2025-02-22 ⋅ 阅读:(17) ⋅ 点赞:(0)

事务回滚是保证数据一致性的关键机制,但如果事务回滚失效,可能会导致数据不一致的问题。我会用简单易懂的方式来讲解,帮助你理解事务回滚失效的常见原因及解决方法。


1. 什么是Spring事务回滚?

在Spring中,事务管理是通过声明式事务控制来实现的。当你在方法上使用@Transactional注解时,Spring会为这个方法创建一个事务。如果方法执行过程中发生异常,Spring会自动回滚事务,撤销所有在事务中所做的更改,以保证数据的一致性。


2. 事务回滚失效的常见原因

2.1 非受检查异常(Unchecked Exceptions)

Spring默认只在遇到非受检查异常(如RuntimeException及其子类)时才会回滚事务。如果方法抛出的是受检查异常(如Exception),Spring不会自动回滚事务。

解决方法:

如果你想让事务在受检查异常时也回滚,可以在@Transactional注解中指定rollbackFor属性,阿里的规范插件也会有下划波浪线作为提醒:

@Transactional(rollbackFor = Exception.class)
public void myMethod() {
    // 方法逻辑
}

2.2 事务传播行为(Propagation Behavior)

事务传播行为决定了当前事务与已存在事务的关系。如果配置不当,可能会导致事务回滚失效。

常见的事务传播行为:
  • REQUIRED(默认):如果存在当前事务,则加入该事务;否则,创建一个新的事务。

  • REQUIRES_NEW:创建一个新的事务,与当前事务独立。

  • SUPPORTS:如果存在当前事务,则加入该事务;否则,以非事务方式执行。

解决方法:

确保事务传播行为符合你的业务需求。例如,如果你希望在新事务中执行某些操作,可以使用REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void myMethod() {
    // 方法逻辑
}

2.3 嵌套事务

如果一个事务方法调用了另一个事务方法,可能会导致事务回滚失效。特别是当内部方法的异常没有被外部方法捕获时,外部事务可能不会回滚。

解决方法:
  • 确保内部方法的异常能够被外部方法捕获。

  • 使用合适的事务传播行为来管理嵌套事务。

2.4 事务管理器配置问题

如果事务管理器没有正确配置,可能会导致事务回滚失效。

解决方法:

确保事务管理器的配置正确。例如,如果你使用的是JPA,确保DataSourceEntityManagerFactory正确配置:

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory);
}

2.5 数据库事务隔离级别

事务隔离级别决定了当前事务与其他事务的隔离程度。如果隔离级别设置不当,可能会导致事务回滚失效。

解决方法:

确保事务隔离级别符合你的业务需求。例如,如果你需要防止脏读,可以设置为READ_COMMITTED

@Transactional(isolation = Isolation.READ_COMMITTED)
public void myMethod() {
    // 方法逻辑
}

2.6 数据库配置问题

某些数据库配置问题也可能导致事务回滚失效。例如,数据库的autocommit模式如果被设置为true,可能会导致事务自动提交,从而无法回滚。

解决方法:

确保数据库的autocommit模式被设置为false

DataSource dataSource = ...;
dataSource.setAutocommit(false);

2.7 修饰符不是public

有时候使用了private等其他不是public的修饰符则会导致无法回滚。

解决方法:

将修饰符改为public即可。

2.8 相同类中的多个方法调用

调用A类的handler1,在A类中的handler1又调了A类中的handler2,导致handler1和handler2的事务都不执行。

解决方法:

由于代理导致的,可以通过写一个组合的方法;如果非要这么调用,也可以通过SpringUtils.getBean(A.class).handler2()的方式进行调用。


3. 总结

事务回滚失效可能是由多种原因引起的,包括异常类型、事务传播行为、嵌套事务、事务管理器配置、事务隔离级别和数据库配置等。为了避免事务回滚失效,你可以:

  • 使用rollbackFor属性指定需要回滚的异常类型。

  • 确保事务传播行为符合业务需求。

  • 管理嵌套事务,确保异常能够被正确捕获。

  • 配置正确的事务管理器。

  • 设置合适的事务隔离级别。

  • 确保数据库配置正确。

  • 修饰符改为public。

  • 组合两个事务或通过springUtils获取class后再调用。