1. 程式人生 > >高併發,業務量大的業務場景下,資料庫減庫存的解決方案

高併發,業務量大的業務場景下,資料庫減庫存的解決方案

1,使用者下單購買商品的情況下,如果有多個人同時下單,減除庫存的情況下,如果遇到了減去庫存的併發問題,這個時候應該怎麼處理呢?

傳統的業務流程場景下,處理流程是這樣的: 1,庫存查詢,通過dao查詢商品庫存,返回庫存數量 select gnum from goods where gid=#{gid} 2,判斷庫存是否充足,充足進行庫存減扣 update goods set gnum=gnum-#{num} where gid=#{gid}但是在減去庫存的時候往往會出現一些意想不到的錯誤,出錯後程序設計可能會有“重試”機制,但是在重試時,可能會得到錯誤的資料,導致重複減扣或者庫存為負數。

重試導致錯誤的根本原因

,是因為“扣減”操作是一個非冪等的操作,不能夠重複執行,改成設定操作則不會有這個問題: 如下,假如使用者購買三件商品,通過資料庫查詢,返回商品餘量為5,然後通過邏輯計算減去三件商品餘2,然後在設定數量2到資料庫持久化 1,庫存查詢,通過dao查詢商品庫存,返回庫存數量為5 select gnum from goods where gid=#{gid} 2,判斷庫存是否充足,充足進行邏輯庫存減扣,設定資料庫(邏輯計算5-3=2,new_num=2) update goods set gnum=#{new_num} where gid=#{gid}

這樣雖然避免了程式出錯,“重試”機制的減扣沒有導致資料出現錯誤,但是如果使用者發生了併發的購買動作(秒殺類業務特別容易出現),流程如下:

使用者A和使用者B併發購買商品,此時同時查詢資料庫庫存數量為5 使用者A購買了3個庫存,於是庫存要設定為2 使用者B購買了2個庫存,於是庫存要設定為3 此時場景,應該是五個商品剛好售賣完,儲存應該為0,但是這兩個設定庫存的介面併發執行,庫存會先變成2,再變成3,導致資料不一致(實際賣出了5件商品,但庫存只扣減了2,最後一次設定庫存會覆蓋和掩蓋前一次併發操作)

根本原因是,設定操作發生的時候,沒有檢查實際庫存與查詢出來的庫存有沒有變化,理論上: 庫存為5時,使用者A的庫存設定才能成功 庫存為5時,使用者B的庫存設定才能成功

實際執行的時候: 庫存為5,使用者A的set goods=2確實應該成功 庫存變為2了,使用者B的set goods=3應該失敗掉

所以,在資料量較大的情況下,減庫存應該是以下這種方案: update goods set gnum=#{new_num} where gid=#{gid} 修改為: update goods set gnum=#{new_num} where gid=#{gid} and gnum=#{old_num} 這樣修改後,使用者A設定庫存為2了,使用者B再去設定庫存,通過條件gnum=#{old_num}判斷條件已經不滿足了,從而保證了資料的一致性。

總結: 在業務複雜,資料量大,併發量大的情況下,庫存扣減容易引發資料的不一致,常見的優化方案有兩個:

  • 呼叫“設定庫存”介面,能夠保證資料的冪等性
  • 在實現“設定庫存”介面時,需要加上原有庫存的比較,才允許設定成功,能解決高併發下庫存扣減的一致性問題