轉載:https://blog.csdn.net/weixin_43681591/article/details/86531870
首先我們要知道超賣的原因是什么:超賣的原因主要是用戶下的訂單的數目和我們要促銷的商品的數目不一致導致的,每次總是訂單的數比我們的促銷商品的數目要多。究其深層原因,是因為數據庫底層的寫操作和讀操作可以同時進行,雖然寫操作默認帶有隱式鎖(即對同一數據不能同時進行寫操作)但是讀操作默認是不帶鎖的,所以當用戶1去修改庫存的時候,用戶2依然可以都到庫存為1,所以出現了超賣現象。
解決方案有以下幾種:
第一種方案是:在每次下訂單前我們判斷促銷商品的數量夠不夠,不夠不允許下訂單,更改庫存量時加上一個條件,只更改商品庫存大於 0 的商品的庫存,當時我們使用 ab 進行壓力測試,當並發超過 500,訪問量超過 2000 時,還是會出現超賣現象。
第二種方案是:使用 mysql 的事務加排他鎖來解決,首先我們選擇數據庫的存儲引擎為 innoDB,使用的是排他鎖實現的,剛開始的時候我們測試了下共享鎖,發現還是會出現超賣的現象。有個問題是,當我們進行高並發測試時,對數據庫的性能影響很大,導致數據庫的壓力很大。
第三種方案是:使用文件鎖實現。當用戶搶到一件促銷商品后先觸發文件鎖,防止其他用戶進入,該用戶搶到促銷品后再解開文件鎖,放其他用戶進行操作。這樣可以解決超賣的問題,但是會導致文件得 I/O 開銷很大。
第四種方案是:最后我們使用了 redis 的隊列來實現。將要促銷的商品數量以隊列的方式存入 redis 中,每當用戶搶到一件促銷商品則從隊列中刪除一個數據,確保商品不會超賣。這個操作起來很方便,而且效率極高,最終我們采取這種方式來實現。
使用的話我還是建議使用第四種方案。