您现在的位置是:主页 > Web前端技术 > Web前端技术

spring中@Transactional的失效场景有哪些开发技术

IDCBT2022-01-05服务器技术人已围观

简介小编给大家分享一下spring中@Transactional的失效场景有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了

小编给大家分享一下spring中@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()获取代理对象

    道理类似于方式2,就是为了通过代理来访问内部方法

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

    这个没什么好说的,都没有被Spring管理成为IOC容器中的一个bean,更别说被事务切面代理到了。

    这种Bug看上去比较蠢,但没准真的有人犯错。

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

    这类失效场景主要聚焦在框架本身在解析

    标签:

    很赞哦! ()

本栏推荐