spring中事务为什么会回滚?什么原理?
事务回滚是保证数据一致性的关键机制,但如果事务回滚失效,可能会导致数据不一致的问题。我会用简单易懂的方式来讲解,帮助你理解事务回滚失效的常见原因及解决方法。
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,确保DataSource
和EntityManagerFactory
正确配置:
@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后再调用。