最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

圖解MySQL中樂觀鎖扣減庫存原理

 更新時間:2023年04月13日 08:56:16   作者:JAVA前線  
這篇文章主要為大家詳細介紹了MySQL中樂觀鎖扣減庫存原理的相關(guān)知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下

1 基礎(chǔ)知識

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

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

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

1.1 共享鎖與排它鎖

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

select lock in share mode

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

select for update
update
delete
insert

共享鎖與排它鎖兼容關(guān)系如下表:

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

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í)行查詢均可以獲取預(yù)期結(jié)果:

(2) 讀寫互斥

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

(3) 寫寫互斥

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

1.2 當(dāng)前讀與快照讀

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

快照讀不需要加鎖,讀取的是記錄可見版本,有可能是歷史版本??梢灶惐扔唵慰煺眨脩粝聠沃笊唐穬r格發(fā)生了變化,但是訂單快照不會改變。實現(xiàn)當(dāng)前讀語句如下:

select

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

select lock in share mode
select for update
update
delete
insert

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

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

第一次程序?qū)嵗l(fā)出當(dāng)前讀請求,存儲引擎返回滿足where條件的第一條記錄并加鎖,程序?qū)嵗侔l(fā)出更新請求,存儲引起操作完成響應(yīng)成功。依次執(zhí)行直到所有滿足where條件記錄執(zhí)行完成為止。

這里我們做一些引申,RR級別提供了兩種機制避免幻讀問題:第一種方式是快照讀,讀取的是當(dāng)前事務(wù)開啟時的快照。第二種方式針對當(dāng)前讀,防止幻讀依賴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é)合第一章節(jié)知識進行進一步分析:

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

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

3 扣減庫存原理

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

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

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

以上就是圖解MySQL中樂觀鎖扣減庫存原理的詳細內(nèi)容,更多關(guān)于MySQL樂觀鎖扣減庫存的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

荃湾区| 阜新| 南充市| 多伦县| 横山县| 比如县| 梁河县| 安西县| 常德市| 金塔县| 无为县| 晋宁县| 叙永县| 怀来县| 贺州市| 霍林郭勒市| 万全县| 章丘市| 阳春市| 南木林县| 宁国市| 扎鲁特旗| 公主岭市| 洛浦县| 辉县市| 涟源市| 修文县| 勐海县| 米易县| 浦县| 海宁市| 顺昌县| 安多县| 略阳县| 瓮安县| 政和县| 登封市| 宽城| 杭锦旗| 宜良县| 左云县|