总结spring中12种@Transactional的失效场景

一、失效场景集一:代理不生效

Spring中对注解解析都是基于代理的,如果目标方法无法被Spring代理到,那么它将无法被Spring进行事务管理。

Spring生成代理的方式有两种:

  • 基于接口的JDK动态代理,要求目标代理类需要实现一个接口才能被代理
  • 基于实现目标类子类的CGLIB代理

Spring在2.0之前,目标类如果实现了接口,则使用JDK动态代理方式,否则通过CGLIB子类的方式生成代理。

而在2.0版本之后,如果不在配置文件中显示的指定spring.aop.proxy-tartget-class的值,默认情况下生成代理的方式为CGLIB,如下图

 代理不生效场景:

1)将注解标注在接口方法上

@Transactional是支持标注在方法与类上的。一旦标注在接口上,对应接口实现类的代理方式如果是CGLIB,将通过生成子类的方式生成目标类的代理,将无法解析到@Transactional,从而事务失效。

这种错误我们还是犯得比较少的,基本上我们都会将注解标注在接口的实现类方法上。

(2)被final、static关键字修饰的类或方法

CGLIB是通过生成目标类子类的方式生成代理类的,被final、static修饰后,无法继承父类与父类的方法。

(3)类方法内部调用

事务的管理是通过代理执行的方式生效的,如果是方法内部调用,将不会走代理逻辑,也就调用不到了。如图

createUser中调用了内部方法createUser1,并且createUser1方法上设置了事务传播策略为:REQUIRES_NEW,但是因为是内部直接调用,createUser1不能不代理处理,无法进行事务管理。在createUser1方法抛出异常后就插入数据失败了。

但是这种操作在我们业务开发的过程中貌似还挺常见的,怎么样才能保证其成功呢?

方式1:新建一个Service,将方法迁移过去,有点麻瓜。

方式2:在当前类注入自己,调用createUser1时通过注入的userService调用

方式3:通过AopContext.currentProxy()获取代理对象、

 

 (4)当前类没有被Spring管理

二、失效场景集二:框架或底层不支持的功能

这类失效场景主要聚焦在框架本身在解析@Transactional时的内部支持。如果使用的场景本身就是框架不支持的,那事务也是无法生效的。

(1)非public修饰的方法

我们在标有@Transactional的任意方法上打个断点,在idea内能看到事务切面点如下图所示

点击去这个方法,在开头有这么一个调用

 继续点进去

 

不支持非public修饰的方法进行事务管理。 

(2)多线程调用

跟上面一样的的操作,我们能够逐层进入到TransactionAspectSupport.prepareTransactionInfo方法。

注意看以下这段话

 事务信息是跟线程绑定的。

其实多线程与事务本就是矛盾的,多线程本就需要保证线程安全,如果事务影响到其他线程的数据有违线程安全。

(3)数据库本身不支持事务

比如Mysql的Myisam存储引擎是不支持事务的,只有innodb存储引擎才支持。

这个问题出现的概率极其小,因为Mysql5之后默认情况下是使用innodb存储引擎了。

但如果配置错误或者是历史项目,发现事务怎么配都不生效的时候,记得看看存储引擎本身是否支持事务。

(4)未开启事务

这个也是一个比较麻瓜的问题,在Springboot项目中已经不存在了,已经有DataSourceTransactionManagerAutoConfiguration默认开启了事务管理。

但是在MVC项目中还需要在applicationContext.xml文件中,手动配置事务相关参数。如果忘了配置,事务肯定是不会生效的。

三、失效场景集三:错误使用@Transactional

(1)错误的传播机制

Spring支持了7种传播机制,分别为:

上面不支持事务的传播机制为:PROPAGATION_SUPPORTS,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER。

如果配置了这三种传播方式的话,在发生异常的时候,事务是不会回滚的。

(2)rollbackFor属性设置错误

默认情况下事务仅回滚运行时异常和Error,不回滚受检异常(例如IOException)。

因此如果方法中抛出了IO异常,默认情况下事务也会回滚失败。

我们可以通过指定@Transactional(rollbackFor = Exception.class)的方式进行全异常捕获。

(3)异常被内部catch

(4)嵌套事务

四、总结

参考:https://www.jb51.net/article/233682.htm 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值