SpringBoot中事务(@Transactional)与try{}catch(){}finally{}之间存在的问题

前言:

本次问题发生在用户出售下单过程中,出现了并发操作,导致同一个产品出现了过量销售(本来只卖10台结果买了12台),在出售方法中已经加了事物(@Transactional)注解,并且方法内部使用了Redis分布式锁做了防并发操作

问题代码:

public TradeResult<String> add(StartSaleOrderDTO dto, TUser user) throws Exception {

  //TODO 先进行加锁操作,防止数据发生并发
  boolean lock = buyService.lockNoExpire(dto.getId().longValue());
  LogUtil.info("出售订单进行加锁操作,订单号:[{}],返回状态:[{}],投放用户:[{}]",dto.getId(),lock,user);
  if (!lock){
  LogUtil.info("当前订单有人在正在出售,请稍后再试,入参:[{}],投放用户:[{}]",dto,user);
    return TradeResult.error(TradeResultEnum.DEFAULT_EXE,"当前订单有人在正在出售,请稍后再试");
  }
  buy = buyService.getOne(queryWrapper);

  try{
    //内部逻辑

    //解锁
    buyService.unlock(dto.getId().longValue());

    return TradeResult.success("创建成功");
  }catch (Exception ex){
    LogUtil.info("当前订单出售异常,入参:[{}],投放用户:[{}],异常原因:[{}]",dto,user,ex.toString());
    buyService.unlock(dto.getId().longValue());
    throw new Exception("出售失败,请稍后再试!");
  }finally {
    //解锁操作
    buyService.unlock(dto.getId().longValue());
  }
}

问题:

为什么做了防并发和事物之后依然出现了并发操作。

发生原因:

经过对代码逻辑的梳理和测试最终发现问题出现在finally方法上,因为事务是作用于整个方法,会先执行finally后在执行提交事物操作,当finall执行完成后锁已经被释放了,然而此时事物还未提交,恰好此时有一个用户提交了订单,导致获取的数据还是事务未提交之前的数据,结果就导致了同一个订单被过量销售的问题

SpringBoot中事务(@Transactional)与try{}catch(){}finally{}之间存在的问题

 

解决方案:

去掉finally

 

上一篇:.net core 时间与时间戳的转换


下一篇:ABP VNext框架基础知识介绍(1)--框架基础类继承关系