如何解決高並發秒殺的超賣問題


由秒殺引發的一個問題
  • 秒殺最大的一個問題就是解決超賣的問題。其中一種解決超賣如下方式:
  • update goods set num = num - 1 WHERE id = 1001 and num > 0
    我們假設現在商品只剩下一件了,此時數據庫中  num = 1;
     
    但有100個線程同時讀取到了這個  num = 1,所以100個線程都開始減庫存了。
     
    但你會最終會發覺, 其實只有一個線程減庫存成功,其他99個線程全部失敗。
     
    為何?
     
    這就是MySQL中的排他鎖起了作用。
     
    排他鎖又稱為寫鎖,簡稱X鎖,顧名思義,排他鎖就是不能與其他所並存, 如一個事務獲取了一個數據行的排他鎖,其他事務就不能再獲取該行的其他鎖,包括共享鎖和排他鎖,但是獲取排他鎖的事務是可以對數據就行讀取和修改。
    就是類似於我在執行update操作的時候,這一行是一個事務 (默認加了排他鎖)。 這一行不能被任何其他線程修改和讀寫

 

  • 第二種解決超賣的方式如下
  • select version from goods WHERE id= 1001
    update goods set num = num - 1, version = version + 1 WHERE id= 1001 AND num > 0 AND version = @version(上面查到的version);
    這種方式采用了 版本號的方式,其實也就是 CAS的原理。
     
    假設此時version = 100, num = 1; 100個線程進入到了這里,同時他們select出來版本號都是version = 100。
     
    然后直接update的時候,只有其中一個先update了,同時更新了版本號。
     
    那么其他99個在更新的時候,會發覺version並不等於上次select的version,就說明version被其他線程修改過了。那么我就放棄這次update
     
    • 第三種解決超賣的方式如下
     利用redis的單線程預減庫存。比如商品有100件。那么我在redis存儲一個k,v。例如 <gs1001, 100>
     
    每一個用戶線程進來,key值就減1,等減到0的時候,全部拒絕剩下的請求。
     
    那么也就是只有100個線程會進入到后續操作。所以一定不會出現超賣的現象
     
    • 總結
     
    可見第二種CAS是失敗重試,並無加鎖。應該比第一種加鎖效率要高很多。 類似於Java中的Synchronize和CAS


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM