MYSQL處理高並發,防止庫存超賣(圖解)


 搶購場景完全靠數據庫來扛,壓力是非常大的,我們在最近的一次搶購活動改版中,采用了redis隊列+mysql事務控制的方案,畫了個簡單的流程圖:

 

QQ截圖20141230150409

 

 

 

       先來就庫存超賣的問題作描述:一般電子商務網站都會遇到如團購、秒殺、特價之類的活動,而這樣的活動有一個共同的特點就是訪問量激增、上千甚至上萬人搶購一個商品。然而,作為活動商品,庫存肯定是很有限的,如何控制庫存不讓出現超買,以防止造成不必要的損失是眾多電子商務網站程序員頭疼的問題,這同時也是最基本的問題。

從技術方面剖析,很多人肯定會想到事務,但是事務是控制庫存超賣的必要條件,但不是充分必要條件。

舉例:

總庫存:4個商品

請求人:a、1個商品 b、2個商品 c、3個商品

程序如下:

beginTranse(開啟事務)
try{
    $result = $dbca->query('select amount from s_store where postID = 12345');
    if(result->amount > 0){
        //quantity為請求減掉的庫存數量
        $dbca->query('update s_store set amount = amount - quantity where postID = 12345');
    }
}catch($e Exception){
    rollBack(回滾)
}
commit(提交事務)

       以上代碼就是我們平時控制庫存寫的代碼了,大多數人都會這么寫,看似問題不大,其實隱藏着巨大的漏洞。數據庫的訪問其實就是對磁盤文件的訪問,數據庫中的表其實就是保存在磁盤上的一個個文件,甚至一個文件包含了多張表。例如由於高並發,當前有三個用戶a、b、c三個用戶進入到了這個事務中,這個時候會產生一個共享鎖,所以在select的時候,這三個用戶查到的庫存數量都是4個,同時還要注意,mysql innodb查到的結果是有版本控制的,在其他用戶更新沒有commit之前(也就是沒有產生新版本之前),當前用戶查到的結果依然是就版本;

然后是update,假如這三個用戶同時到達update這里,這個時候update更新語句會把並發串行化,也就是給同時到達這里的是三個用戶排個序,一個一個執行,並生成排他鎖,在當前這個update語句commit之前,其他用戶等待執行,commit后,生成新的版本;這樣執行完后,庫存肯定為負數了。但是根據以上描述,我們修改一下代碼就不會出現超買現象了,代碼如下:

beginTranse(開啟事務)
try{
    //quantity為請求減掉的庫存數量
    $dbca->query('update s_store set amount = amount - quantity where postID = 12345');
    $result = $dbca->query('select amount from s_store where postID = 12345');
    if(result->amount < 0){
       throw new Exception('庫存不足');
    }
}catch($e Exception){
    rollBack(回滾)
}
commit(提交事務)


免責聲明!

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



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