Spring事务哪些情况会失效?
Spring事务失效
访问权限问题
java的访问权限主要有4种:private、default、protected、public,如果事务方法的访问权限不是定义为public,这样会导致事务失效,因为spring要求被代理方法必须是public的。翻开源码,可以看到,在
AbstractFallbackTransactionAttributeSource
类的computeTransactionAttribute
方法中有个判断,如果目标方法不是public,则返回null,即不支持1
2
3
4
5
6
7protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
} else {
//........
}
}方法用final修饰
如果事务方法用final修饰,会导致事务失效,因为spring事务底层原理使用了aop也就是通过jdk动态代理或者cglib,帮助我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法,而添加事务功能。
对象没有被spring管理
使用spring事务的前提是:对象要被spring管理,需要创建bean实例。如果类没有加@Controller、@Service、@Component、@Repository等注解,即该类没有交给spring去管理,那么它的方法就不会生成事务。
表不支持事务
如果MySQL使用的存储引擎是myisam,这样的话是不支持事务的,因为myisam存储引擎不支持事务。
方法内部调用
1
2
3
4
5
6
7
8
9
10
11@Service
public class OrderServiceImpl implements OrderService{
public void update(Order order){
this.updateOrder(order);
}
@Transactional
public void updateOrder(Order order){
//更新操作
}
}如上面代码所示,update方法上没有加@Transactional注解,调用有@Transactional注解的updateOrder方法,updateOrder方法上的事务会失效。因为发生了自身调用,调用该类自己的方法,而没有经过spring的代理类,只有在外部调用事务才会生效。
解决:
再加一个serviece,将内部调用改为外部调用
使用编程式事务
使用AopContexct.currentProxy()获取代理对象
1
2
3
4
5
6
7
8
9
10
11@Service
public class OrderServiceImpl implements OrderService{
public void update(Order order){
((OrderService)AopContexct.currentProxy()).updateOrder(order);
}
@Transactional
public void updateOrder(Order order){
//更新操作
}
}
未开启事务
如果是spring项目,则需要再配置文件中手动配置事务相关参数,如果忘记了配置,事务肯定是失效的。如果是spingboot项目,那么不需要手动配置。因为springboot已经在
DataSourceTransactionManagerAutoConfiguration
类中帮我们开启了事务。吞了异常
有时候事务不会回滚,有可能是在代码中手动catch了异常,因为开发者自己捕获了异常,又没有手动抛出,把异常吞掉了,这种情况喜爱spring事务不会回滚。如果想要spring事务能够正常回滚必须抛出它能够处理的异常