<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          商品庫存的扣除過程,如何防止超賣?

          共 926字,需瀏覽 2分鐘

           ·

          2022-02-15 16:24

          點擊下方“IT牧場”,選擇“設為星標”

          作者:iloveoverfly

          來源:blog.csdn.net/new_com/article/details/105568124


          在商品購買的過程中,庫存的抵扣過程,一般操作如下:


          1. select根據(jù)商品id查詢商品的庫存。

          2. 根據(jù)下單的數(shù)量,計算庫存是否足夠,如果存庫不足則拋出庫存不足的異常,如果庫存足夠,則減去扣除的庫存得到最新的庫存剩余值。

          3. set設置最新的庫存剩余值。


          上述過程的偽代碼如下:

          // 根據(jù)商品id獲取商品剩余庫存select stock_remaing from stock_table where id=${goodsId}; // 操作庫存// 比較庫存if(stock_remaing    // 拋出庫存不足的異常}else{// 抵扣以后的庫存值int new_stock=stock_remaing - quantity;} // 根據(jù)商品id設置計算后的庫存update stock_table  set stock_remaing =${new_stock} id=${goodsId};


          # 并發(fā)修改數(shù)據(jù)庫存超賣


          如果數(shù)據(jù)庫事務的隔離級別不是串行化(serializable),根據(jù)事務的特性,在并發(fā)修改的時候,可能會出現(xiàn)寫覆蓋的問題。


          假設,商品的剩余庫存stock_remaing 為100,客戶A下單20,客戶B下單30,在并發(fā)扣庫存的時候,可能存在超賣。如果客戶A和客戶B同時獲取剩余庫存為100,則會出現(xiàn)事務后提交的值會覆蓋前一個客戶提交的值,有可能剩余的庫存是80或者70。流程如下:


          # 加鎖更新存庫


          為了在事務控制中,防止寫覆蓋,你會想到使用select for update的方式,將該商品的庫存鎖住,然后執(zhí)行余下的操作。


          流程如下:



          以上,使用悲觀鎖方式,在分布式服務中,如果并發(fā)情況比較高的時候,扣減庫存的操作是串行操作,效率很低。


          # 使用樂觀鎖的方式更新


          在更新的時候,使用(CAS+版本號更新)+重試條件(重試次數(shù)或者重試時間限制)樂觀鎖的方式更新庫存。此時,如果,客戶A和客戶B同時讀取到庫存剩余100,在更新的時候,有一個操作會失敗。流程如下:


          該種方式可以大大提高并發(fā)性,也可以保證數(shù)據(jù)的一致性;通過重試次數(shù)和重試時間的條件控制,可以防止過多的重試帶來的數(shù)據(jù)庫壓力。


          # 可以使用直接遞減的方式執(zhí)行么?


          在抵扣庫存的時候,有的人提議不執(zhí)行select,計算,set三段式的操作,直接扣減的方式,并且對于扣減到小于零的情況作了判斷。偽代碼如下:

          update stock_table set remaing_stock=remaing_stock-${quantity} where id =商品idand remaing_stock>${quantity};


          在分布式服務調(diào)用中,因為網(wǎng)絡異常,獲取服務器異常,可能在微服務調(diào)用時,存在服務重試。例如,場景的網(wǎng)關(guān)超時,服務重試機制。此時,該種方式不滿足冪等性,而存在多扣的情況。例如,同一用戶扣減庫存時,服務重試,極端情況下,該用戶扣減庫存操作執(zhí)行多次,則就出現(xiàn)了商品超賣。


          # 可以使用redis進行庫存的抵扣么?


          由于沒有研究過redis源碼,對于這種方式參考了大牛的回復,答案是可以使用redis的事務性扣減余額,但在CAS機制上比mysql沒有優(yōu)勢,高性能是因為其內(nèi)存存儲的原因,帶來的副作用是數(shù)據(jù)有丟失風險。

          干貨分享

          最近將個人學習筆記整理成冊,使用PDF分享。關(guān)注我,回復如下代碼,即可獲得百度盤地址,無套路領取!

          ?001:《Java并發(fā)與高并發(fā)解決方案》學習筆記;?002:《深入JVM內(nèi)核——原理、診斷與優(yōu)化》學習筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領域驅(qū)動設計速成)》?007:全部?008:加技術(shù)群討論

          加個關(guān)注不迷路

          喜歡就點個"在看"唄^_^

          瀏覽 23
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产乱╳╳Av | 国产精彩无码视频 | 国产免费黄色电影在线观看 | 欠欠欠久久精品一级探花 | 欧美大鸡吧视频 |