Spring事务传播机制
回顾
之前我们学习了Spring如何进行事务的实现和运用,今天我们来学习Spring事务的传播机制
简单介绍
Spring事务的传播机制就是当存在多个事务的时候,且多个事务方法存在调用关系,事务是如何在这些方法中进行传播的
事务的传播机制有哪些
@Transactional注解支持事务传播机制的设置,通过propagation属性来指定传播行为,
以A方法调用B方法为例,A⽅法运⾏时, 会开启⼀个事务. 当A调⽤B时, B⽅法本⾝也有事务, 此时B⽅法运⾏时, 是加⼊A的事务, 还是创建⼀个新的事务呢(使用自己的事务)?这个就涉及到了事务的传播机制.
Spring事务传播有以下七种机制:
Propagation.REQUIRED
默认的事务传播级别. 无论外层是否有事务,内层都需要有事务,外层没有就为自己新建事务,外层有就融入到外层的事务中
Propagation.SUPPORTS
外层没有事务,内层也不需要事务,外层有事务,内存就融入外层事务
Propagation.MANDATORY
要求外层必须有事务,且将内存融入到外层事务中,否则报错
Propagation.REQUIRES_NEW
无论外层是否有事务,内层都有事务,如果外层有事务,不会融入外层,而是自己新建事务,内外相互独立(日志记录)
Propagation.NOT_SUPPORTED
无论外层是否有事务,内层都不使用事务
Propagation.NEVER
外层存在事务,内层会抛出异常
Propagation.NESTED
无论外层是否有事务,内层都需要有事务,外层没有就为自己新建事务,外层有就融入到外层的事务中
与require的区别:nested隔离级别的内层出现异常,外层不会出现影响
实例
上面其中机制,我们只需要重点掌握两个:
REQUIRED
REQUIRES_NEW
REQUIRED
@RestController
public class PropagationController {
@Autowired
private UserInfoService userInfoService;
@Autowired
private LogInfoService logInfoService;
@Transactional( propagation = Propagation.REQUIRED)
@RequestMapping("/insertInfo")
public void insertInfo(String userName,String password){
userInfoService.insert(userName,password);
logInfoService.insert(userName,"用户注册成功");
}
}
@Service
public class LogInfoService {
@Autowired
private LogInfoMapper logInfoMapper;
@Transactional( propagation = Propagation.REQUIRED)
public Integer insert(String userName, String op) {
Integer i = 10/0;
return logInfoMapper.insert(userName,op);
}
}
@Service
public class UserInfoService {
@Autowired
private UserInfoMapper userInfoMapper;
@Transactional( propagation = Propagation.REQUIRED)
public Integer insert(String userName, String password) {
return userInfoMapper.insert(userName,password);
}
}
运⾏程序,程序报错,发现数据库没有插⼊任何数据
流程描述:
- insertInfo⽅法开始事务
- ⽤⼾注册, 插⼊⼀条数据 (执⾏成功) (和insertInfo使⽤同⼀个事务)
- 记录操作⽇志, 插⼊⼀条数据(出现异常, 执⾏失败) (和insertInfo使⽤同⼀个事务)
- 因为步骤3出现异常, 事务回滚. 步骤2和3使⽤同⼀个事务 所以步骤2的数据也回滚了
REQUIRES_NEW
将上述代码中将上述UserService和LogService的传播机制改为 REQUIRES_NEW
运行程序,我们观察程序,可以看到,user_info中已经成功新增了一条数据,但是log_info中却并没有成功
这是因为REQUIRES_NEW的调用方与被调用着的事务是独立的,之间互不影响.
NEVER
将UserService中的事务传播机制改为NEVER
运行程序,程序报错,数据也没有插入成功,这是因为NEVER的调用方不能有事务,否则会报错,并回滚
NESTED
将UserService和LogService中的传播机制改为NESTED
运行程序,发现似乎和REQUIRED一样,但是当我们手动给LogService进行回滚,就会发现,日志表新增失败了,但是用户表注册成功了,也就是说,调用方的事务包含被调用者的事务,但是被调用者的事务也是一个独立的事务,因此可以实现局部回滚
REQUIRED和NESTED的区别
整个事务如果全部执⾏成功, ⼆者的结果是⼀样的
如果事务⼀部分执⾏成功, REQUIRED加⼊事务会导致整个事务全部回滚. NESTED嵌套事务可以实现局部回滚, 不会影响上⼀个⽅法中执⾏的结果