使用 Spring 框架的声明式事务管理-演道网

本网站用的阿里云ECS,推荐大家用。自己搞个学习研究也不错

记录一个上周遇到的小问题。


后端开发免不了要和事务打交道,比较常用的就是利用 Spring 框架的声明式事务管理,简单的说就是在需要事务管理的类或方法上添加 @Transactional 注解,然后在配置类上添加 @EnableTransactionManagement注解(这里配置采用 JavaConfig 的方式,如果是 XML, 是要在 XML 文件中添加)。然后 Spring 框架会利用 AOP 在相关方法调用的前后进行事务管理。

一直以来也没出什么岔子,直到。。。。。。。。

上周写了段大概长下面样纸的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class GiraffeServiceImpl implements GiraffeService {

public void A(List giraffes) {

for (Giraffe giraffe : giraffes) {
B(giraffe);
}
}

@Transactional("transactionManager")
public void B(Giraffe giraffe) {
// Step 1: update something
// Step 2: insert something
// Step 3: update something
}
}

大概就是 Service 中有一个方法 A,会内部调用方法 B, 方法 A 没有事务管理,方法 B 采用了声明式事务,通过在方法上声明 Transactional 的注解来做事务管理。

然鹅,通过下面的 Junit 测试方法 A 的时候发现方法 B 的事务并没有开启, 而直接调用方法 B 事务是正常开启的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class GiraffeServiceTest{

@Autowired
private GiraffeService giraffeService;

// 没有开启事务
@Test
public void testA() {
giraffeService.A();
}

// 正常开启事务
@Test
public void testB() {
giraffeService.B();
}
}

T^T

问了下明佳和超哥之后,终于有点明白了🤔

Spring 在加载目标 Bean 的时候,会为声明了 @Transactional 的 目标 Bean 创造一个代理类,而目标类本身并不能感知到代理类的存在。调用通过 Spring 上下文注入的 Bean 的方法, 并不是直接调用目标类的方法。
不是
而是先调用代理类的方法,再调用目标类的。
是

对于加了@Transactional注解的方法来说,在调用代理类的方法时,会先通过拦截器TransactionInterceptor开启事务,然后在调用目标类的方法,最后在调用结束后,TransactionInterceptor 会提交或回滚事务,大致流程如下图。
transaction manager

而对于第一段的代码,我在方法 A 中调用方法 B,实际上是通过“this”的引用,也就是直接调用了目标类的方法,而非通过 Spring 上下文获得的代理类,所以。。。事务是不会开启滴。

解决办法也蛮简单,通过实现ApplicationContextAware接口获得 Spring 的上下文,然后获得目标类的代理类,通过代理类的对象,调用方法 B,即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class GiraffeServiceImpl implements GiraffeService,ApplicationContextAware{

@Setter
private ApplicationContext applicationContext;

public void A(List giraffes) {

GiraffeService service = applicationContext.getBean(GiraffeService.class);
for (Giraffe giraffe : giraffes) {
service.B(giraffe);
}
}

@Transactional("transactionManager")
public void B(Giraffe giraffe) {
// Step 1: update something
// Step 2: insert something
// Step 3: update something
}
}

stackoverflow 上也有相关的问题:
@Transactional – What happens in background?
@Transactional Annotation : Self Invocation

唉,都快写完了,还没等来 wuli 悦儿

wuli 悦儿

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

未经允许不得转载:演道网 » 使用 Spring 框架的声明式事务管理-演道网

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册