<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>

          高并發(fā)下,如何防止庫存超賣?

          共 854字,需瀏覽 2分鐘

           ·

          2022-02-26 00:53

          點(diǎn)擊關(guān)注公眾號,Java干貨及時送達(dá)

          作者:iloveoverfly

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


          在商品購買的過程中,庫存的抵扣過程,一般操作如下:
          1. select根據(jù)商品id查詢商品的庫存。
          2. 根據(jù)下單的數(shù)量,計(jì)算庫存是否足夠,如果存庫不足則拋出庫存不足的異常,如果庫存足夠,則減去扣除的庫存得到最新的庫存剩余值。
          3. set設(shè)置最新的庫存剩余值。

          上述過程的偽代碼如下:

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

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

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

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

          加鎖更新存庫

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

          流程如下:

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

          使用樂觀鎖的方式更新

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

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

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

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

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

          在分布式服務(wù)調(diào)用中,因?yàn)榫W(wǎng)絡(luò)異常,獲取服務(wù)器異常,可能在微服務(wù)調(diào)用時,存在服務(wù)重試。

          例如,場景的網(wǎng)關(guān)超時,服務(wù)重試機(jī)制。此時,該種方式不滿足冪等性,而存在多扣的情況。

          例如,同一用戶扣減庫存時,服務(wù)重試,極端情況下,該用戶扣減庫存操作執(zhí)行多次,則就出現(xiàn)了商品超賣。

          可以使用redis進(jìn)行庫存的抵扣么?

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

          ??

          1、來自谷歌的開發(fā)心得:所有SQL和代碼,都沒必要藏著掖著

          2、用了這么久的 Chrome,你不會還沒掌握這個功能吧?

          3、一個比SpringBoot快44倍的Java框架

          4、QQ最近上線的兩個新功能,把我人都看傻了!

          5、SpringBoot 三大開發(fā)工具,你都用過么?

          點(diǎn)分享

          點(diǎn)收藏

          點(diǎn)點(diǎn)贊

          點(diǎn)在看

          瀏覽 100
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  色播播五月天 | 国产成人一区二区 | 91大神小宝探花一区二区三区 | 欧美一区二区三区四区视频 | 乱伦小说五月天 |