@Transactional的一个不生效问题


2、了解一下@Transactional注解


事物的注解方式:@Transactional

@Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解所使用。

@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。


看到这里我发现@Override注解和@Transactional注解一起使用不会导致@Transactional不生效。

3、追击为什么  @Transactional 注解应该只被应用到 public 方法上!!!


如下图1:

Spring 事务实现机制(基于CglibAopProxy


@Transactional 只能应用到 public 方法才有效

只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是因为在使用 Spring AOP 代理时,Spring 在调用在图 1 中的 TransactionInterceptor 在目标方法执行前后进行拦截之前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 通过这个类获取表 1. @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。

清单 4. AbstractFallbackTransactionAttributeSource


1
2
3
4
5
protected TransactionAttribute computeTransactionAttribute(Method method,
     Class<?> targetClass) {
         // Don't allow no-public methods as required.
         if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;}


这个方法会检查目标方法的修饰符是不是 public,若不是 public,就不会获取@Transactional 的属性配置信息,最终会造成不会用 TransactionInterceptor 来拦截该目标方法进行事务管理。


本以为问题得到了解决,但是彬哥补充到,这个案例即使把方法的protected改为public也是不起作用的。

为什么呢?

原因是因为@Transactional是基于springAOP代理实现的,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。process方法是updateParticularsCheckResult方法内部的方法,无法获取到该bean,所以还是不会使@Transactional生效。

终上,该问题导致@Transactional失效有俩个原因,

原因1、@Transactional只能应用在public方法才有效

原因2、 @Transactional不能作用在方法的内部的任何方法上


4、补充

class C1 : 方法a1 ,方法b1


classC2:   方法a2


事务方法a1  事务方法b1   俩者事务都会执行

事务方法a1  非事务方法b1   a1事务会执行

非事务方法a1  事务方法b1   b1事务不会执行


事务方法a1  事务方法a1   俩者事务都会执行

事务方法a1  非事务方法b1   a1事务会执行

非事务方法a1  事务方法b1   b1事务会执行


其中值得深究的是 非事务方法a1  事务方法b1   b1事务不会执行  ,


原因是: 

在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成一个自调用问题。

若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务就会被忽略,不会发生回滚。


这里需要对 Spring 生成的代理对象来管理造成一个自调用问题。解释一下:

在应用系统采用了 -> 调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑;分析这句话 意思也就是要想让spring的声明式@Transactional 生效,必须要经过 拦截器 TransactionInterceptor处理,而自调用问题导致的原因也正是TransactionInterceptor没有 拦截到。


解决方法:

根本原因是 由于使用 Spring AOP 代理造成的。所以替代Spring AOP 代理问题就解决了,

 使用 AspectJ 取代 Spring AOP 代理。


 

 AspectJ 的 xml 配置信息

 


1
2
3
4
5
6
7
8
9
10
< tx:annotation-driven mode = "aspectj" />
< bean id = "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = "dataSource" ref = "dataSource" />
</ bean >
</ bean
class = "org.springframework.transaction.aspectj.AnnotationTransactionAspect"
factory-method = "aspectOf" >
< property name = "transactionManager" ref = "transactionManager" />
</ bean >


同时在 Maven 的 pom 文件中加入 spring-aspects 和 aspectjrt 的 dependency 以及 aspectj-maven-plugin。

 AspectJ 的 pom 配置信息


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
< dependency >
< groupId >org.springframework</ groupId >
< artifactId >spring-aspects</ artifactId >
< version >4.3.2.RELEASE</ version >
</ dependency >
< dependency >
< groupId >org.aspectj</ groupId >
< artifactId >aspectjrt</ artifactId >
< version >1.8.9</ version >
</ dependency >
< plugin >
< groupId >org.codehaus.mojo</ groupId >
< artifactId >aspectj-maven-plugin</ artifactId >
< version >1.9</ version >
< configuration >
< showWeaveInfo >true</ showWeaveInfo >
< aspectLibraries >
< aspectLibrary >
< groupId >org.springframework</ groupId >
< artifactId >spring-aspects</ artifactId >
</ aspectLibrary >
</ aspectLibraries >
</ configuration >
< executions >
< execution >
< goals >
< goal >compile</ goal >
< goal >test-compile</ goal >
</ goals >
</ execution >
</ executions >
</ plugin >


而且使用AspectJ 取代 Spring AOP 代理还可以解决@Transactional 注解只应用到 public 方法的问题。

猜你喜欢

转载自blog.csdn.net/Darrensty/article/details/80285301