1:前言
最近在修改公司支付问题时,碰到一个问题,当支付失败时,业务逻辑没有回滚。很明显没有做事务回滚。可以建模成以下模型:
public class UserServiceImpl implements UserService{
.......
public void addUser(User user){
userTagService.addUserTag(userTag);
userDao.addUser(user);
}
}
userService.addUser方法调用 userTagService.addUserTag方法。我们希望如果userDao.addUser发生异常,该userService.addUser整个方法都可以回滚。Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。
2:spring事务传播类型
解释下:
PROPAGATION_NESTED:只有底层数据源基于JDBC3.0,并且实现者需要支持保存点事务机制。
嵌套事务:当userService.addUser在一个事务下(比如PROPAGATION_REQUIRED),而userTagService.addUserTag申明了(PROPAGATION_NESTED),假设支持保存点,Sping会在addUserTag方法上产生一个内嵌事务,如果它发生异常,事务会回滚到addUserTag执行前的点,但是不会整个事务回滚,内嵌事务是内层事务的一部分,只有提交外层事务时,内嵌事务才能提交。
也就说内嵌事务不能导致外层事务回滚,但是外层事务回滚会影响内嵌事务回滚。
PROPAGATION_REQUIRES_NEW 会启动一个新事务,和外层事务没有关系,有自己的独立隔离级别和锁,不依赖与外部事务,独立提交和回滚,当该事务执行时,外部事务会被挂起,等该事务结束时,外部事务才能继续执行。
3:实际问题
需求:只要在addUser中的对数据库的增删改都要在同一个事务中,同时成功同时失败。但是我们在addUser中又调用了其他service中方法。
分析:如果我们想这两个方法在同一个事务中,在上面的7个事务中我们可以使用PROPAGATION_REQUIRED来申明addUser事务,然后使用PROPAGATION_REQUIRED,PROPAGATION_SUPPORTS,PROPAGATION_MANDATORY来修饰addUserTag方法,但是比较推荐PROPAGATION_REQUIRED
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addUser(User user) {
userTagService.addUserTag(userTag);
userDao.addUser(user);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addUserTag(UserTag userTag) {
try {
userTagMapper.insertUserTag(userTag);
}catch (Exception e){
System.out.println("这里出现异常");
throw new RuntimeException();
}
}
需要说明的一点是:如果要抛出异常一定要抛出 RuntimeException(),如果抛出Exception()不能被spring 捕获。
参考博文: