Spring 事务失效了,怎么办?

网站建设4年前发布
29 0 0

这是小伙伴们在微信上问的一个问题:,20230306105131a90c950463052be96d26725ca8e9ee11e3175c223,这个问题比较典型,让我想到面试时有一个 Spring 事务失效的问题,跟这个原因以及解决方案是一模一样的,因此,抽空整篇文章和小伙伴们分享下。,小伙伴们知道,AOP 底层就是动态代理,动态代理有两种实现方式:,如果被代理的对象有接口,则可以使用 JDK 动态代理,没有接口就可以使用 CGLIB 动态代理。,在 Spring 中,默认情况下,如果被代理的对象有接口,就使用 JDK 动态代理,如果被代理的对象没有接口,则使用 CGLIB 动态代理。,在 Spring Boot 中,2.0 之前也跟 Spring 中的规则一样,2.0 之后则统一都使用 CGLIB 动态代理。,不过这些都是默认的规则,如果有接口,但是你又希望使用 CGLIB 动态代理,通过修改配置,也都是可以实现的:,如果是 XML 配置,想使用 CGLIB 动态代理,可以按如下方式实现:,如果是 Java 配置,想使用 CGLIB 动态代理,可以按如下方式实现:,当然,在新版 Spring Boot 项目中,有接口的类默认就是使用 CGLIB 动态代理的。但是此时如果有接口的类你又想使用 JDK 动态代理,那么可以通过如下配置:,关于 Spring Boot 中的 AOP 代理问题,可以参考去年松哥写的文章:Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理?。,基于第一小节的讲解,小伙伴们知道,当你在项目中用到了 AOP 之后,其实你所以见到的类,并不是原本的类了。,虽然是解决不同的问题,但是有一个共同的点,那就是都是通过自定义注解+ AOP 解决问题的。,现在我就以手把手教你玩多数据源动态切换!为例,来和大家说说这里的动态代理到底是咋回事,没看过这篇文章的小伙伴可以先看下。,小伙伴们看下,我的 UserService 大致上是下面这样:,小伙伴们看到,count() 方法上加了 @DS 注解,所以这个 count() 方法将来是要被自动代理的。换言之,当你在另外一个类中注入 UserService 的时候,其实不是这个 UserService,我 DEBUG 小伙伴们来看一下:,20230306105055d755487672c5670eb36989a5ef461cdd5c8acd181,小伙伴们从图中可以看到,此时我注入的 UserService 并不是真正的 UserService,而是一个通过 CGLIB 动态代理为 UserService 生成的子类,这个子类里边的 count 方法大致逻辑类似下面这样(其实就是 AOP 中的代码,具体小伙伴们可以参考 手把手教你玩多数据源动态切换!一文):,但是,如果我的调用逻辑是这样呢:,小伙伴们来看,count2 方法,这个时候直接在 count2 方法中调用了 count 方法,当然,count2() 方法中的调用也可以写作 this.count();,这样看起来就更明确了,我们调用 count 方法,使用的是当前对象,而当前对象是不包含代理对象中的代码的,我们通过 DEBUG 来看下:,20230306105056f94f8970779a72928c1075f6e147523ec8ff19781,所以,当我们在 count2 中直接调用 count 方法的时候,那么加在 count 方法上的注解就会失效。,这个问题存在于所有使用了 AOP 的地方,存在的原因第二小节已经分析的很清楚了。,解决办法其实也有很多种,最为简单省事的一种,就是在当前类中注入代理对象,然后通过代理对象去调用其他方法,如下:,202303061050570800b5866759c3a97fd96251ff40660fe06fdc392,虽然问题解决了,不过这毕竟不是一个好的解决办法(因为自己中注入自己,在新版 Spring Boot 中要开启循环依赖才能实现),大家在实际开发中,还是要从设计上尽量避免这种问题。,好啦,这个问题搞明白了,那么事务失效这个问题,也不用我多说了吧!,

© 版权声明

相关文章