前言:
本次問題發生在用戶出售下單過程中,出現了並發操作,導致同一個產品出現了過量銷售(本來只賣10台結果買了12台),在出售方法中已經加了事物(@Transactional)注解,並且方法內部使用了Redis分布式鎖做了防並發操作
問題代碼:
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
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