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执行完成后锁已经被释放了,然而此时事物还未提交,恰好此时有一个用户提交了订单,导致获取的数据还是事务未提交之前的数据,结果就导致了同一个订单被过量销售的问题
解决方案:
去掉finally
标签:dto,SpringBoot,Transactional,buyService,longValue,getId,try,finally,user 来源: https://www.cnblogs.com/wutongTree/p/15545966.html