如何正解決庫存超賣問題

2021-08-26 09:38:51 字數 1415 閱讀 5288

begin... try }catch($e exception) commit...

以上**就是我們平時控制庫存寫的**了,大多數人都會這麼寫,看似問題不大,其實隱藏著巨大的漏洞。

下面我們來改造一下**:

begin .... try }catch($e exception) commit....

再優化一下,如:

begin... trycatch($e exception) commit...

但是,使用事務也會帶來效能問題,下面我們來分析一下:

在秒殺的情況下,肯定不能如此高頻率的去讀寫資料庫,會嚴重造成效能問題的必須使用快取,將需要秒殺的商品放入快取中,並使用鎖來處理其併發情況。當接到使用者秒殺提交訂單的情況下,先將商品數量遞減(加鎖/解鎖)後再進行其他方面的處理,處理失敗在將資料遞增1(加鎖/解鎖),否則表示交易成功。當商品數量遞減到0時,表示商品秒殺完畢,拒絕其他使用者的請求。

這個肯定不能直接運算元據庫的,會掛的。直接讀庫寫庫對資料庫壓力太大,要用快取。把你要賣出的商品比如10個商品放到快取中;然後在memcache裡設定乙個計數器來記錄請求數,這個請求書你可以以你要秒殺賣出的商品數為基數,比如你想賣出10個商品,只允許100個請求進來。那當計數器達到100的時候,後面進來的就顯示秒殺結束,這樣可以減輕你的伺服器的壓力。然後根據這100個請求,先付款的先得後付款的提示商品以秒殺完。

首先,多使用者併發修改同一條記錄時,肯定是後提交的使用者將覆蓋掉前者提交的結果了。

如果不採用事務,我們採用資料庫鎖來實現,鎖分為樂觀鎖或者悲觀鎖。

其它思路我們也可以來發揮一下:

除了加鎖的方式也可以使用接收鎖定的方式,思路是在資料庫中設計乙個狀態標識位,使用者在對資料進行修改前,將狀態標識位標識為正在編輯的狀態,這樣其他使用者要編輯此條記錄時系統將發現有其他使用者正在編輯,則拒絕其編輯的請求,類似於你在作業系統中某檔案正在執行,然後你要修改該檔案時,系統會提醒你該檔案不可編輯或刪除。

[結論]

1,不建議在資料庫層面加鎖,建議通過服務端的記憶體鎖(鎖主鍵)。當某個使用者要修改某個id的資料時,把要修改的id存入memcache,若其他使用者觸發修改此id的資料時,讀到memcache有這個id的值時,就阻止那個使用者修改。

2,實際應用中,並不是讓mysql去直面大併發讀寫,會借助「外力」,比如快取、利用主從庫實現讀寫分離、分表、使用佇列寫入等方法來降低併發讀寫。

3,注意防止快取穿透問題。即:如果快取中所存商品的id範圍可知,如100-1000,那麼當我查詢id為<100及1000的商品時,這裡快取中肯定是不存在的,按邏輯肯定會去查db,查到後把資料放到快取。這時問題來了,如果有人故意刷你這個範圍外的東西,這樣每次去查db,併發量上來時,db一定會掛。因此,為了避免這個問題,應在快取放置當前資料存在的記錄id,通過id確定是否需要查詢db。這樣大大減輕了db的壓力。

庫存超賣的解決方案

update sku info set kc kc 1 where sku id and kc 0 在高併發下,多人搶同一庫存,由於資料庫讀寫可以並行執行的原因,會導致修改庫存時,庫存不足出現超賣。悲觀鎖解決 在select加乙個行鎖,與更新庫存操作互斥,保證查詢庫存時,庫存不被修改 在查詢和更新庫...

電商防止庫存超賣解決方案

悲觀鎖,也就是在修改資料的時候,採用鎖定狀態,排斥外部請求的修改。遇到加鎖的狀態,就必須等待。可以採用redis佇列 mysql事務控制的方案,下面是流程圖 mysql的執行 begintranse 開啟事務 try catch e exception commit 提交事務 先執行update鎖住...

秒殺系統防止庫存超賣

第一種 通過資料庫樂觀鎖實現 小型電商 update productstocks set realstock realstock where sku and realstock 0 根據受影響的行數判斷是否執行成功 大型網際網路不是這麼玩的 資料庫有瓶頸 第二種 使用redis 分布式鎖實現 var...