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
|
<
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 方法的问题。