spring @transactional public和自调用方法的问题处理
@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 来拦截该目标方法进行事务管理。
避免 Spring 的 AOP 的自调用问题
在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。见清单 5 举例代码展示。
清单 5.自调用问题举例
1
2
3
4
5
6
7
8
9
10
11
12
|
@Service -->public
class OrderService { private
void insert() { insertOrder(); } @Transactional public
void insertOrder() { //insert
log info //insertOrder //updateAccount } } |
insertOrder 尽管有@Transactional 注解,但它被内部方法 insert 调用,事务被忽略,出现异常事务不会发生回滚。
上面的两个问题@Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP 代理造成的。为解决这两个问题,使用 AspectJ 取代 Spring AOP 代理。
需要将下面的 AspectJ 信息添加到 xml 配置信息中。
清单 6. 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。
清单 7. 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 > |