本文介绍了如何在Spring框架下配置和启动一个嵌套事务,深入探讨了其工作原理及应用场景。
在Spring框架中,事务管理是核心部分之一。本段落将探讨如何在一个已存在的事务上下文中启动新的事务。
考虑以下示例代码:
```java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public void doSomething(UserDO userDo) {
insert(userDo);
doOther();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insert(UserDO userDo) {
userMapper.insert(userDo);
}
public void doOther() {
System.out.println(做一些其它的事,例如调用其它的系统);
}
}
```
在上述代码中,在`doSomething()`方法内调用了带有`@Transactional(propagation = Propagation.REQUIRES_NEW)`注解的`insert(UserDO userDo)`。这表明当执行插入操作时需要启动一个新的事务。
然而,当我们尝试通过调用 `UserService#doSomething()` 来测试这种行为时会发现新事务并没有被开启。这是由于Spring框架中的代理机制决定的:在方法内部直接调用不会触发新的事务管理器创建一个额外的事务上下文。
为了解决这个问题,可以采用以下两种策略:
1. 将`insert(UserDO userDo)`操作从当前类中独立出来,并将其封装到另一个服务类(如 `XxxService`)内。然后在主业务逻辑处理类中注入该外部服务并调用其方法来执行插入操作。
2. 使用Spring AOP提供的代理对象进行间接的方法调用,而非直接通过this关键字访问内部的事务管理方法。
```java
@Transactional(rollbackFor = Exception.class)
public void doSomething(UserDO userDo) {
UserService userService = (UserService) AopContext.currentProxy();
userService.insert(userDo);
doOther();
}
```
在项目启动类上开启代理暴露功能:
```java
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
```
这样,`insert()`方法中的新事务就会生效。
需要注意的是,在Spring Boot 1.x版本中需要通过添加`@EnableTransactionManagement`注解来启用基于AOP的声明式事务管理。而在2.x及以上版本中,默认就启用了这一特性,无需额外配置相关注解。