淺析扣減庫存的方案設計

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你好,我是悟空,今天來探討下扣減庫存的方案。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"生活中,我們總是用各種電商app搶購商品,但是庫存數是很少的,特別是秒殺場景,商品可能就一件,那如何保證不會出現超賣的情況呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"本文已同步至","attrs":{}},{"type":"text","text":":","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/Jackson0714/PassJava-Learning","title":"","type":null},"content":[{"type":"text","text":"https://github.com/Jackson0714/PassJava-Learning","attrs":{}}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"一、扣減庫存的三種方案","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1)下單減庫存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶下單時減庫存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"優點","attrs":{}},{"type":"text","text":":實時減庫存,避免付款時因庫存不足減庫存的問題","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"缺點","attrs":{}},{"type":"text","text":":惡意買家大量下單,將庫存用完,但是不付款,真正想買的人買不到","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2)付款減庫存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下單頁面顯示最新的庫存,下單時不會立即減庫存,而是等到支付時纔會減庫存。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"優點","attrs":{}},{"type":"text","text":":防止惡意買家大量下單用光庫存,避免下單減庫存的缺點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"缺點","attrs":{}},{"type":"text","text":":下單頁面顯示的庫存數可能不是最新的庫存數,而庫存數用完後,下單頁面的庫存數沒有刷新,出現下單數超過庫存數,若支付的訂單數超過庫存數,則會出現支付失敗。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(3)預扣庫存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下單頁面顯示最新的庫存,下單後保留這個庫存一段時間(比如10分鐘),超過保留時間後,庫存釋放。若保留時間過後再支付,如果沒有庫存,則支付失敗。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"優點","attrs":{}},{"type":"text","text":":結合下單減庫存的優點,實時減庫存,且緩解惡意買家大量下單的問題,保留時間內未支付,則釋放庫存。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"缺點","attrs":{}},{"type":"text","text":":保留時間內,惡意買家大量下單將庫存用完。併發量很高的時候,依然會出現下單數超過庫存數。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"二、如何解決惡意買家下單的問題","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的惡意買家指短時間內大量下單,將庫存用完的買家。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1)限制用戶下單數量","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"優點","attrs":{}},{"type":"text","text":":限制惡意買家下單","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"缺點","attrs":{}},{"type":"text","text":":用戶想要多買幾件,被限制了,會降低銷售量","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}},{"type":"strong","attrs":{}},{"type":"strong","attrs":{}}],"text":"(2)標識惡意買家","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"優點","attrs":{}},{"type":"text","text":":賣家設定一個備用庫存,當支付時,庫存已用完,扣減備用庫存數,這就是常見的補貨場景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"缺點","attrs":{}},{"type":"text","text":":因高併發場景下,數據可能存在不一致性的問題","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"三、如何解決下單成功而支付失敗(庫存不足)的問題","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1)備用庫存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"商品庫存用完後,如果還有用戶支付,直接扣減備用庫存。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"優點","attrs":{}},{"type":"text","text":":緩解部分用戶支付失敗的問題","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"缺點","attrs":{}},{"type":"text","text":":備用庫存只能緩解問題,不能從根本上解決問題。另外備用庫存針對普通商品可以,針對特殊商品這種庫存少的,備用庫存量也不會很大,還是會出現大量用戶下單成功卻因庫存不","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"足而支付失敗的問題。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"四、如何解決高併發下庫存超賣的場景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"庫存超賣最簡單的解釋就是多成交了訂單而發不了貨。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"場景:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶A和B成功下單,在支付時扣減庫存,當前庫存數爲10。因A和B查詢庫存時,都還有庫存數,所以A和B都可以付款。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"A和B同時支付,A和B支付完成後,可以看做兩個請求回調後臺系統扣減庫存,有兩個線程處理請求,兩個線程查詢出來的庫存數 inventory=10,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後A線程更新最終庫存數 lastInventory=inventory - 1 = 9,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"B線程更新庫存數 lastInventory=inventory - 1 = 9。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而實際最終的庫存應是8纔對,這樣就出現庫存超賣的情況,而發不出貨。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那如何解決庫存超賣的情況呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1.SQL語句直接更新庫存,而不是先查詢出來,然後賦值","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" UPDATE [庫存表] SET 庫存數 - 1\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2.SQL語句更新庫存時,如果扣減庫存後,庫存數爲負數,直接拋異常,利用事務的原子性進行自動回滾。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3.利用SQL語句更新庫存,防止庫存爲負數","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" UPDATE [庫存表] SET 庫存數 - 1 WHERE 庫存數 - 1 > 0\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果影響條數大於1,則表示扣減庫存成功,否則不更新庫存,並退款。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"五、秒殺場景下如何扣減庫存","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1)下單減庫存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因秒殺場景下,大部分用戶都是想直接購買商品的,可以直接用下單減庫存。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大量用戶和惡意用戶都是同時進行的,區別是正常用戶會直接購買商品,惡意用戶雖然在競爭搶購的名額,但是獲取到的資格和普通用戶一樣,所以下單減庫存在秒殺場景下,惡意用戶下單並不能造成之前說的缺點。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而且下單直接扣減庫存,這個方案更簡單,在第一步就扣減庫存了。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2)將庫存放到redis緩存中","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"查詢緩存要比查詢數據庫快,所以將庫存數放在緩存中,直接在緩存中扣減庫存。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(3)使用量自增方式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以先增加已使用量,然後與設定的庫存進行比較,如果超出,則將使用量減回去。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外其實真實的項目中,用到了更多的機制來保證能夠正常扣減庫存,本篇是拋磚引入,希望大家提出寶貴的建議和方案~。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"本文已同步至","attrs":{}},{"type":"text","text":":","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/Jackson0714/PassJava-Learning","title":"","type":null},"content":[{"type":"text","text":"https://github.com/Jackson0714/PassJava-Learning","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"歡迎關注我的公衆號:「","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}}],"text":"悟空聊架構","attrs":{}},{"type":"text","text":"」","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者簡介:","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"8 年互聯網職場老兵|全棧工程師|90 後超級奶爸|開源踐行者|公衆號萬粉原創號主","attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"藍橋簽約作者,著有《JVM 性能調優實戰》專欄,手寫了一套 7 萬字 SpringCloud 實戰總結和 3 萬字分佈式算法總結。歡迎關注我的公衆號「悟空聊架構」,免費獲取資料學習。","attrs":{}}]}],"attrs":{}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章