溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL中樂觀鎖扣減庫存原理是什么

發(fā)布時間:2023-04-13 09:27:07 來源:億速云 閱讀:108 作者:iii 欄目:開發(fā)技術

這篇文章主要講解了“MySQL中樂觀鎖扣減庫存原理是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“MySQL中樂觀鎖扣減庫存原理是什么”吧!

    1 基礎知識

    在電商系統(tǒng)中扣減庫存是一步非常關鍵的操作,例如秒殺系統(tǒng)中一定要防止超賣情況出現(xiàn),如果商家設置了100件庫存但是最后賣出1000件,這樣就會產生資金損失。在扣減庫存時一般使用如下語句:

    udpate goods set stock = stock - #{acquire} 
    where sku_id = #{skuId} and stock - #{acquire} >= 0

    這條語句可以保護庫存資源防止超賣,我們不妨分析這條語句為什么生效。本文使用MySQL Innodb引擎進行演示,隔離級別為可重復讀。

    1.1 共享鎖與排它鎖

    共享鎖(share Lock)又被稱為讀鎖,實現(xiàn)共享鎖語句如下:

    select lock in share mode

    排它鎖(exclusive Lock)又被稱為寫鎖,實現(xiàn)排它鎖語句如下:

    select for update
    update
    delete
    insert

    共享鎖與排它鎖兼容關系如下表:

    MySQL中樂觀鎖扣減庫存原理是什么

    我們通過實例分析上述兼容關系,首先建一張測試表并寫入測試數(shù)據:

    CREATE TABLE `test_account` (
      `id` bigint(20) NOT NULL,
      `name` varchar(20) DEFAULT NULL,
      `account` bigint(20) DEFAULT NULL,
      `version` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert  into `test_account`(`id`,`name`,`account`,`version`) values (1,'A',100,1);
    insert  into `test_account`(`id`,`name`,`account`,`version`) values (2,'B',200,1);
    insert  into `test_account`(`id`,`name`,`account`,`version`) values (3,'C',300,1);

    (1) 讀讀兼容

    共享鎖與共享鎖之間兼容,在如下實例中session1在t3時刻,session2在t4時刻執(zhí)行查詢均可以獲取預期結果:

    MySQL中樂觀鎖扣減庫存原理是什么

    (2) 讀寫互斥

    共享鎖與排它鎖之間互斥,在如下實例中session1在t3時刻加共享鎖,可以正確讀取結果,但是session2在t4時刻嘗試加排它鎖,但是此時鎖被session1占有,session2需要等待,當session1長時間不釋放鎖時,session2拋出鎖超時異常:

    MySQL中樂觀鎖扣減庫存原理是什么

    (3) 寫寫互斥

    排它鎖與排它鎖之間互斥,在如下實例中session1在t3時刻加排它鎖,可以正確讀取結果,但是session2在t4時刻嘗試加排它鎖,但是此時鎖被session1占有,session2需要等待,當session1長時間不釋放鎖時,session2拋出鎖超時異常:

    MySQL中樂觀鎖扣減庫存原理是什么

    1.2 當前讀與快照讀

    MySQL Innodb存儲引擎實現(xiàn)基于多版本并發(fā)控制協(xié)議MVCC,在MVCC并發(fā)控制中讀操作可以分成快照讀與當前讀。

    快照讀不需要加鎖,讀取的是記錄可見版本,有可能是歷史版本??梢灶惐扔唵慰煺?,用戶下單之后商品價格發(fā)生了變化,但是訂單快照不會改變。實現(xiàn)當前讀語句如下:

    select

    當前讀需要加鎖,讀取的是記錄最新版本,加鎖保證了在讀取時,當前記錄不會被其它事務修改。實現(xiàn)當前讀語句如下:

    select lock in share mode
    select for update
    update
    delete
    insert

    我們通過一個實例分析快照讀和當前讀,session2在t4時刻修改記錄并在t5時刻提交,session1在t6時刻進行了快照讀,讀取的是本事務開始時結果100,在t7時刻進行了當前讀,讀取的是記錄最新版本結果101:

    MySQL中樂觀鎖扣減庫存原理是什么

    當前讀流程是怎么樣的呢?我們以update為例進行分析當前讀流程:

    MySQL中樂觀鎖扣減庫存原理是什么

    第一次程序實例發(fā)出當前讀請求,存儲引擎返回滿足where條件的第一條記錄并加鎖,程序實例再發(fā)出更新請求,存儲引起操作完成響應成功。依次執(zhí)行直到所有滿足where條件記錄執(zhí)行完成為止。

    這里我們做一些引申,RR級別提供了兩種機制避免幻讀問題:第一種方式是快照讀,讀取的是當前事務開啟時的快照。第二種方式針對當前讀,防止幻讀依賴Next-Key Lock機制。

    2 樂觀鎖原理

    我們通過一個問題將上述知識整合起來:有兩個線程在同一時刻執(zhí)行如下語句,請問id=1這條記錄account值會不會成功扣減兩次?

    update test_account set account = account - 100, version = version + 1 
    where id = 1 and version = 1

    上述語句使用了樂觀鎖,我們知道樂觀鎖就是對資源進行保護的,所以答案是不會扣減兩次,但是不能就此止步,需要結合第一章節(jié)知識進行進一步分析:

    MySQL中樂觀鎖扣減庫存原理是什么

    t2時刻session1和session2同時執(zhí)行update操作,由于update會加排它鎖,所以兩者只能有一個成功:session1成功,session2阻塞等待排它鎖釋放。

    t3時刻session1提交事務釋放排它鎖,此時session2獲取到鎖進行當前讀,但是此時id=1記錄version值已經變成了2,執(zhí)行語句已經查詢不到待更新數(shù)據,所以沒有記錄發(fā)生更新。

    3 扣減庫存原理

    如果理解了第二章節(jié)樂觀鎖原理,那么扣減庫存原理已經顯而易見,我們假設商品只剩下1件庫存,如果兩個線程同時執(zhí)行扣減庫存,會發(fā)生超賣的情況嗎?

    MySQL中樂觀鎖扣減庫存原理是什么

    t2時刻session1和session2同時執(zhí)行updatek扣減庫存,由于update會加排它鎖,所以兩者只能有一個成功:session1成功,session2阻塞等待排它鎖釋放。

    t3時刻session1提交事務釋放排它鎖,此時session2獲取到鎖進行當前讀,但是此時商品1庫存已經變?yōu)?,已經不滿足(where stock - 1 >= 0)條件,執(zhí)行語句已經查詢不到待更新數(shù)據,所以沒有記錄發(fā)生更新。

    感謝各位的閱讀,以上就是“MySQL中樂觀鎖扣減庫存原理是什么”的內容了,經過本文的學習后,相信大家對MySQL中樂觀鎖扣減庫存原理是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI