之前我们学习了Spring如何进行事务的实现和运用,今天我们来学习Spring事务的传播机制
Spring事务的传播机制就是当存在多个事务的时候,且多个事务方法存在调用关系,事务是如何在这些方法中进行传播的
@Transactional注解支持事务传播机制的设置,通过propagation属性来指定传播行为,
以A方法调用B方法为例,A⽅法运⾏时, 会开启⼀个事务. 当A调⽤B时, B⽅法本⾝也有事务, 此时B⽅法运⾏时, 是加⼊A的事务, 还是创建⼀个新的事务呢(使用自己的事务)?这个就涉及到了事务的传播机制.
Spring事务传播有以下七种机制:
默认的事务传播级别. 如果A存在事务, 则B加⼊该事务. 如果A没有事务, 则创建⼀个新的事务(事务中包含AB).
如果A存在事务, 则B加⼊该事务. 如果A没有事务, 则A,B以都以⾮事务的⽅式继续运⾏.
强制性. 如果A存在事务, 则B加⼊该事务. 如果A没有事务, 则抛出异常.
创建⼀个新的事务(B) 如果A存在事务, 则把A事务挂起. 也就是说不管A⽅法是否开启事务, Propagation.REQUIRES_NEW修饰的B⽅法都会新开启一个事务, 且开启的事务相互独⽴, 互不⼲扰,就算A用A的事务,B用B的事务,A没有就算了
B以⾮事务⽅式运⾏, 如果A存在事务, 则把A事务挂起(不⽤).
以⾮事务⽅式运⾏, 如果A存在事务, 则抛出异常.
如果A存在事务, 则创建⼀个事务作为A事务的嵌套事务来运⾏. 如果A没有事务, 则该取值等价于PROPAGATION_REQUIRED
上面其中机制,我们只需要重点掌握两个:
REQUIRED
REQUIRES_NEW
@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);
}
}
运⾏程序,程序报错,发现数据库没有插⼊任何数据
流程描述:
将上述代码中将上述UserService和LogService的传播机制改为 REQUIRES_NEW
运行程序,我们观察程序,可以看到,user_info中已经成功新增了一条数据,但是log_info中却并没有成功
这是因为REQUIRES_NEW的调用方与被调用着的事务是独立的,之间互不影响.
将UserService中的事务传播机制改为NEVER
运行程序,程序报错,数据也没有插入成功,这是因为NEVER的调用方不能有事务,否则会报错,并回滚
将UserService和LogService中的传播机制改为NESTED
运行程序,发现似乎和REQUIRED一样,但是当我们手动给LogService进行回滚,就会发现,日志表新增失败了,但是用户表注册成功了,也就是说,调用方的事务包含被调用者的事务,但是被调用者的事务也是一个独立的事务,因此可以实现局部回滚
整个事务如果全部执⾏成功, ⼆者的结果是⼀样的
如果事务⼀部分执⾏成功, REQUIRED加⼊事务会导致整个事务全部回滚. NESTED嵌套事务可以实现局部回滚, 不会影响上⼀个⽅法中执⾏的结果