SpringBoot中事務(@Transactional)與try{}catch(){}finally{}之間存在的問題


前言:

本次問題發生在用戶出售下單過程中,出現了並發操作,導致同一個產品出現了過量銷售(本來只賣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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM