Spring事务失效的几种场景
往期推荐
符号引用和直接引用、强引用、软引用、弱引用、虚引用-CSDN博客
已老实!再学消息队列、死信队列-CSDN博客
synchronized如何实现可重入,和Lock区别-CSDN博客
Mysql索引失效的几种场景、回表、索引覆盖、索引下推-CSDN博客
1. 未启用Spring事务管理功能或bean没有被spring管理
2. @Transactional修饰的方法非public或被final、static修饰
3. 同类的方法A直接调用同类的事务方法B
spring事务是通过Spring AOP实现的,对需要spring管理事务的bean生成了代理对象,然后通过代理对象拦截了目标方法的执行,在方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。如果方法A直接调用方法B则是this调用,即该类的类对象,就不是代理对象。可以通过
Service
类中注入自己,或者通过AopContext.currentProxy()
获取代理对象来解决。
4. 抛出的异常类型错误
在业务方法进行异常抛出,spring会自动对事务进行回滚,那么问题来了,抛出哪些异常spring会回滚事务呢?默认情况下,spring遇到RuntimeException和Error的事务才会回滚。因为spring认为RuntimeException和Error是不可预期的错误,而而受检异常是可预期的错误,可以通过业务逻辑即可解决。
当然也可以自定义回滚异常类型@Transactional(rollbackFor = {异常类型列表})
5. 异常被捕获处理
spring感知到指定异常被抛出才会进行回滚,如果在方法内部捕获处理掉异常,事务就不会回滚
@Transactional
public void m1(){
事务操作1
try{
事务操作2,内部抛出了异常
}catch(Exception e){
log.error(....)
}
}
正确做法是捕获处理掉异常后抛出来,如下:
@Transactional
public void m1(){
事务操作1
try{
事务操作2,内部抛出了异常
}catch(Exception e){
log.error(....)
throw e
}
}
6. 事务操作和@Transactional方法不在同一线程
@Transactional
public void m1() {
new Thread() {
一系列事务操作
}.start();
}
7. 事务传播行为设置不对
spring默认事务传播行为默认是required,事务方法A内部调用事务方法B,如果方法A存在事务则方法B加入方法A的事务,否则创建新事务。如果非事务方法A调用事务方法B,事务传播级别为NOT_SUPPORT,因为方法A当前不存在事务,则方法B虽然有@Transactional注解,但仍然以非事务去执行。