MySQL行鎖范圍分析(行鎖、間隙鎖、臨鍵鎖)

MySQL 中鎖的概念

排它鎖(Exclusive Lock)

X 鎖,也稱為寫鎖,若事務T對對象A加上X鎖,則只允許T讀取和修改A,其他任何事物都不能再對A 加任何鎖,直到T釋放A上的鎖。
SELECT…FOR UPDATE 對讀取的行記錄加一個X鎖,其他事務不能對已鎖定的行加上任何鎖。

共享鎖(Shared Lock)

**S 鎖,**也稱為讀鎖,若事務T對數據對象A加上S鎖,則事務T可以讀A,但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。
SELECT…LOCK IN SHARE MODE對讀取的行記錄加一個S鎖,其他事務可以向被鎖定 的行加S鎖,但是如果加X鎖,則會被阻塞。

活鎖

事務T1封鎖了R,T2又請求封鎖R,于是T2等待,T3也請求封鎖R,當T1釋放了R 上的鎖,系統首先批準了T3的請求,T2繼續等待,這就是活鎖。

死鎖

事務T1封鎖了R1,T2封鎖了R2,T1又請求封鎖R2,因為T2已經封鎖了R2,于是T1等待T2釋放R2上的鎖,接著T2又申請封鎖R1,因為T1已經封鎖了R1,T2只能等待T1釋放R1上的鎖,這就是死鎖。
解決死鎖的方法
一次封鎖法 每個事務必須將所有要使用的數據全部加鎖,否則就不能執行,弊端 加大封鎖范圍,降低了并發速度。

樂觀鎖

總是假設最好的情況,在事務提交前不會對數據進行鎖定,而是在更新數據時會進行版本或時間戳的比較,以確定數據是否被其他事務修改過。如果數據沒有被修改,則允許提交;如果數據被修改,則需要進行沖突解決

悲觀鎖

總是假設最壞的情況,在整個事務過程中,假設其他事務會對數據進行修改,因此在讀取或修改數據時,會先對數據進行鎖定,以防止其他事務對數據進行干擾(排它鎖、共享鎖都是悲觀鎖,共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉讓給其它線程

MySQL 行鎖加鎖的分析

版本使用 MySQL 8.2.0
MySQL InnoDB 中支持三種行鎖的方式:行鎖(Record Lock)、間隙鎖(Gap Lock)、臨鍵鎖(Next-Key Lock),默認加的是臨鍵鎖,但是會根據不同的查詢條件進行優化。創建一個 user 表用來測試,表中 id 是主鍵索引,name 是唯一索引,salary 是普通索引,gender 沒有索引。

idnamesalarygender
10惠月48000
20光濟50000
30杰霖55000
40紫妤60000
50娜溱70000

創建表并插入數據

CREATE TABLE `user`  (`id` int(11) NOT NULL,`name` varchar(255) DEFAULT NULL,`salary` int DEFAULT NULL,`gender` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE,INDEX `salary`(`salary`) USING BTREE,UNIQUE INDEX `name`(`name` ASC) USING BTREE
);INSERT INTO `user` VALUES (10, '惠月', 48000, '女');
INSERT INTO `user` VALUES (20, '光濟', 50000, '男');
INSERT INTO `user` VALUES (30, '杰霖', 55000, '男');
INSERT INTO `user` VALUES (40, '紫妤', 62000, '女');
INSERT INTO `user` VALUES (50, '娜溱', 75000, '女');

加鎖情況

-- 普通的select查詢是快照讀,不加鎖
SELECT * FROM user WHERE id=30;
-- 查詢時給主鍵索引加S共享鎖時,是當前讀
SELECT * FROM user WHERE id=30 LOCK IN SHARE MODE;
-- 查詢時加 X排他鎖,為當前讀
SELECT * FROM user WHERE id=30 FOR UPDATE

執行 SELECT * FROM … FOR UPDATE 會對表加上 IX 寫意向鎖,表示有可能會對這些記錄進行寫操作,并且給記錄加一個X,REC_NOT_GAP,鎖定了該條數據。 執行SELECT * FROM … FOR SHARE 會對表加上一個 IS 讀意向鎖,并且會給記錄加一個S,REC_NOT_GAP。

主鍵索引

主索引等值查詢,數據存在的情況

事務 1

BEGIN;
SELECT * FROM user WHERE id=30 FOR UPDATE;
-- SELECT * FROM user WHERE id=40 FOR SHARE;
-- ROLLBACK

查看鎖的情況

-- mysql 8
SELECT * FROM performance_schema.data_locks;-- mysql 5.7
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

image.png
1、表鎖是意向寫鎖
2、數據加行鎖
各字段意思:
INDEX_NAME 鎖定索引的名稱 PRIMARY 說明是主鍵索引
LOCK_TYPE 鎖的類型,RECORD 行鎖 、 TABLE 表鎖
LOCK_MODE 鎖的模式,IS 讀意向鎖、IX 寫意向鎖、S 讀鎖,又稱共享鎖、X 寫鎖,又稱排它鎖、GAP 間隙鎖。
**LOCK_DATA **要鎖定的數據,當 LOCK_TYPE 是 RECORD行鎖時。當鎖在主鍵索引上時,顯示主鍵索的值。當鎖是在輔助索引上時,顯示主索引和輔助索引的值。

LOCK_MODELOCK_DATA鎖范圍
X,REC_NOT_GAP40id=40 行鎖
X,GAP40id=40 間隙鎖,不包含 40(前開后開)
X40id=40 臨鍵鎖,包含 40(前開后閉)

事務 2
1、會對主索引 id=30 添加行鎖

BEGIN;
-- 更新會失敗,因為事務 1 對 id=30 加行鎖。
UPDATE user SET salary = 56000 WHERE id = 30;

主索引等值查詢,數據不存在的情況

事務 1

BEGIN;
SELECT * FROM user WHERE id=31 FOR UPDATE; -- 數據庫中沒有id=30的記錄

查看加鎖情況
image.png
1、表加的是意向寫鎖
2、id 加的是 GAP Lock,范圍是(30, 40)
注意
LOCK_MODE 是 X,GAP 表示間隙鎖,LOCK_DATA 是 40 表示鎖定的范圍是在 id 為 40 之前的間隙
事務 2
1、會鎖住主索引 id=31 所在的間隙

BEGIN;
-- 可以執行成功
UPDATE `bostore`.`user` SET `salary` = 56000.00 WHERE `id` = 30;
UPDATE `bostore`.`user` SET `salary` = 63000.00 WHERE `id` = 40;
-- 執行失敗
INSERT INTO `bostore`.`user` VALUES (33, '六零', 68000.00, '女');

主索引范圍查詢,前閉后開情況

事務 1

BEGIN;
SELECT * FROM user WHERE id>=30 AND id<33 FOR UPDATE;

查看鎖情況
image.png
1、 表示 IX 意向寫鎖
2、id=30 是行鎖
3、id=40 加的是 GAP Lock,范圍是(30, 40)
事務 2

BEGIN;
-- 會阻塞
UPDATE user SET salary = 57000.00 WHERE id = 30;
INSERT INTO user VALUES (35, '六零', 68000.00, '女');
INSERT INTO user VALUES (33, '合吧', 64000.00, '女');
-- 不會阻塞
UPDATE user SET salary = 63000.00 WHERE id = 40;

主索引范圍查詢,前開后閉情況

事務 1

BEGIN;
SELECT * FROM user WHERE id>30 AND id<=40 FOR UPDATE;

查看鎖情況
image.png
1、表加的是意向寫鎖
2、id=40 加 NEXT-Key Lock,范圍是(30, 40]
事務 2

BEGIN;
-- 會阻塞
UPDATE user SET salary = 63000 WHERE id = 40;
INSERT INTO user VALUES (35, '六零', 68000, '女');
INSERT INTO user VALUES (33, '合吧', 64000, '女');-- 不會阻塞
UPDATE user SET salary = 57000 WHERE id = 30;
UPDATE user SET salary = 78000 WHERE id = 50;
INSERT INTO user VALUES (53, '考拉', 84000, '女');

普通索引

普通索引(普通索引只針對表中的單一列進行索引,普通索引可以是唯一的,也可以不唯一,普通索引對于等值查詢(例如WHERE column = value)和范圍查詢(例如WHERE column > value)都能提供較好的性能提升)

普通索引等值查詢,數據存在的情況

事務 1

BEGIN;
SELECT * FROM user WHERE salary = 62000 FOR UPDATE;

查看鎖情況
image.png
1、 表加意向寫鎖 IX
2、 索引salary加臨鍵鎖,范圍是(55000, 62000]
3、 主鍵 id = 40 加行鎖
4、 索引salary加間隙鎖,范圍是(62000, 75000)
事務 2
1、 主鍵 id=40 加了行鎖,不能更新和刪除

-- 修改id=40有行鎖會阻塞
UPDATE user SET salary = 63000 WHERE id = 40;
UPDATE user SET name="紫是" where salary = 62000;

2、salary 在(55000, 62000] 范圍加了 NEXT-Key Lock(針對該范圍的 id 也會加鎖),insert 時salary 在此范圍,會阻塞
image.png
3、salary 在(62000, 75000)范圍加了 GAP Lock(避免幻讀),insert 時salary 在此范圍,會阻塞
image.png
4、 插入 salary=55000時,id<30可以不阻塞,id>30會阻塞

-- id=40  salary=62000 之前有臨鍵鎖(55000, 62000]
-- 是對salary的鎖,但是整個區間都會被鎖住包括主索引id
INSERT INTO user VALUES (35, '六零', 55000, '女'); -- 阻塞
INSERT INTO user VALUES (51, '哈西', 55000, '女'); -- 阻塞
-- id=30  salary=55000 之前沒有間隙鎖
INSERT INTO user VALUES (29, '湖西', 55000, '女'); -- 不阻塞

5、 插入 salary=62000時,會阻塞

INSERT INTO user VALUES (39, '哈子', 62000, '女');
INSERT INTO user VALUES (44, '靠是', 62000, '女');
INSERT INTO user VALUES (55, '西歐', 62000, '女');
-- 自增id時也是會阻塞
INSERT INTO `bostore`.`user`(`name`, `salary`, `gender`) VALUES ('學律', 62000, '女');

6、插入 salary=75000時,id<50 會阻塞,id>50 不阻塞

-- LOCK_MODE為X,GAP 
-- LOCAK_DATA為75000, 50 表示 要插入salary為75000,id<50時會加鎖,即會阻塞
INSERT INTO user VALUES (29, '合吧', 75000, '女');
-- id > 50 不會阻塞
INSERT INTO user VALUES (51, '歐下', 75000, '女');

7、當salary 不在(55000, 62000] 和(62000, 75000)范圍時,id 不會加鎖

INSERT INTO user VALUES (31, '湖西', 54000, '女');
INSERT INTO user VALUES (49, '離下', 54000, '女');
INSERT INTO user VALUES (45, '的大', 76000, '女');
UPDATE user SET salary = 78000 WHERE id = 50;-- id < 30 和 salary < 55000 不阻塞
INSERT INTO user VALUES (29, '六零', 50000, '女');
-- id > 50 和 salary > 75000 不阻塞
INSERT INTO user VALUES (63, '合吧', 94000, '女');

普通索引等值查詢,數據不存在的情況

事務 1

BEGIN;
SELECT * FROM user WHERE salary = 60000 FOR UPDATE;

查看鎖情況
image.png
1、表加意向寫鎖
2、salary 加間隙鎖,范圍是(55000, 62000)
事務 2
1、salary 在(55000, 62000)范圍加了 GAP Lock,insert 時salary 在此范圍,會阻塞
image.png
2、插入 salary=55000時,id<30可以不阻塞,id>30會阻塞

INSERT INTO user VALUES (35, '六零', 55000, '女'); -- 阻塞
INSERT INTO user VALUES (51, '哈西', 55000, '女'); -- 阻塞
-- id=30  salary=55000 之前沒有間隙鎖
INSERT INTO user VALUES (29, '湖西', 55000, '女'); -- 不阻塞

3、插入 salary=62000時,id<40 會阻塞,id>40 不阻塞

-- id < 40 會阻塞
INSERT INTO user VALUES (39, '合吧', 62000, '女');
-- id > 40 不會阻塞
INSERT INTO user VALUES (41, '歐下', 62000, '女');

4、當 salary 不在(55000, 62000),id 不會加鎖

INSERT INTO user VALUES (31, '湖西', 54000, '女');
INSERT INTO user VALUES (39, '離下', 63000, '女');
UPDATE user SET salary = 63000 WHERE id = 40;-- id < 30 和 salary < 55000 不阻塞
INSERT INTO user VALUES (29, '六零', 50000, '女');
-- id > 40 和 salary > 62000 不阻塞
INSERT INTO user VALUES (41, '合吧', 65000, '女');

普通索引范圍查詢,前閉后開的情況

事務 1

BEGIN;
SELECT * FROM user WHERE salary>=55000 AND salary<62000 FOR UPDATE;

查看鎖情況
image.png
1、表加意向寫鎖
2、salary 加 NEXT-Key Lock 范圍是(50000, 55000]
3、salary 加 NEXT-Key Lock 范圍是(55000, 62000]
4、id=30 加行鎖
事務 2
1、 插入 salary=50000時,id<20可以不阻塞,id>20會阻塞

INSERT INTO user VALUES (19, '六零', 50000, '女'); -- 不阻塞
INSERT INTO user VALUES (21, '哈西', 50000, '女'); -- 阻塞
INSERT INTO user VALUES (41, '湖西', 50000, '女'); -- 阻塞

2、 插入 salary=55000時,會阻塞

INSERT INTO user VALUES (29, '哈子', 55000, '女');
INSERT INTO user VALUES (35, '靠是', 55000, '女');
INSERT INTO user VALUES (44, '西歐', 55000, '女');
-- 自增id時也是會阻塞
INSERT INTO `bostore`.`user`(`name`, `salary`, `gender`) VALUES ('學律', 55000, '女');

3、 插入 salary=62000時,id<40 會阻塞,id>40 不阻塞

-- 阻塞
INSERT INTO user VALUES (39, '合吧', 62000, '女');
-- 不阻塞
INSERT INTO user VALUES (41, '歐下', 62000, '女');

4、當salary 不在(50000, 55000] 和(55000, 62000]范圍時,id 不會加鎖

INSERT INTO user VALUES (31, '湖西', 44000, '女');
INSERT INTO user VALUES (49, '離下', 44000, '女');
INSERT INTO user VALUES (45, '的大', 66000, '女');-- id < 20 和 salary < 50000 不阻塞
INSERT INTO user VALUES (19, '六零', 40000, '女');
-- id > 40 和 salary > 62000 不阻塞
INSERT INTO user VALUES (53, '合吧', 94000, '女');

5、id=30 加行鎖,不能刪除和更新

UPDATE user SET salary = 56000 WHERE id = 30;
UPDATE user SET name="紫下" where salary = 55000;

普通索引范圍查詢,前開后閉的情況

事務 1

BEGIN;
SELECT * FROM user WHERE salary>55000 AND salary<=62000 FOR UPDATE;

查看鎖情況
image.png
1、表加意向寫鎖
2、salary 加 NEXT-Key Lock 范圍是(55000, 62000]
3、salary 加 NEXT-Key Lock 范圍是(62000, 75000]
4、id=40 加行鎖
事務 2 的加鎖情況和上面類似

沒有索引的情況

BEGIN;
SELECT * FROM user WHERE gender='男' FOR UPDATE;

查看加鎖情況
image.png
InnoDB 的鎖是加上在索引上的,沒有索引的時候,就會給所有的記錄都加上鎖 NEXT-Key Lock,相當于表鎖。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213816.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213816.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213816.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

風控之Android設備指紋技術

標識性參數——Android ID、IMEI、OAID非標識性參數 非標識性參數——手機運營商 1 設備指紋 簡單來講&#xff0c;設備指紋是指用于標識出該設備的設備特征。可以是單一設備特征&#xff0c;也可以是多種設備特征的組合&#xff0c;以方便風控系統對設備的唯一性進行識別。…

產品入門第一講:Axure的安裝以及基本使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一個在CSDN分享筆記的博主。&#x1f4da;&#x1f4da; ??? &#x1f31f;在這里&#xff0c;我要推薦給大家我的專欄《Axure》。&#x1f3af;&#x1f3af; &#x1f680;無論你是編程小白&#xff0c;還是有…

未來教師行業發展前景

親愛的老師們&#xff0c;你是否對未來教師行業的發展前景感到好奇和期待&#xff1f;作為一名老師&#xff0c;我深知教育行業的重要性和挑戰&#xff0c;但同時也看到了其中蘊含的巨大機遇。 一、技術融合與在線教育 技術的飛速發展正在改變著教育的面貌。在線教育平臺的崛起…

算法基礎十一

組合 給定兩個整數 n 和 k&#xff0c;返回范圍 [1, n] 中所有可能的 k 個數的組合。 示例 1&#xff1a; 輸入&#xff1a;n 4, k 2 輸出&#xff1a; [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 示例 2&#xff1a; 輸入&#xff1a;n 1, k 1 輸出&#xff1a;[[1]…

用C語言了解文件那些下 ‘流‘ 事

本篇會加入個人的所謂‘魚式瘋言’??????魚式瘋言:??????此瘋言非彼瘋言,而是理解過并總結出來通俗易懂的大白話,我會盡可能的在每個概念后插入魚式瘋言,幫助大家理解的&#xff0c;可能說的不是那么嚴謹.但小編初心是能讓更多人能接受我們這個概念 前言 &#…

uniapp實戰 —— 自定義頂部導航欄

效果預覽 下圖中的紅框區域 范例代碼 src\pages.json 配置隱藏默認頂部導航欄 "navigationStyle": "custom", // 隱藏默認頂部導航src\pages\index\components\CustomNavbar.vue 封裝自定義頂部導航欄的組件&#xff08;要點在于&#xff1a;獲取屏幕邊界…

理解Go中的指針

引言 當你用Go編寫軟件時,你將編寫函數和方法。你可以將數據作為參數傳遞給這些函數。有時,函數需要數據的本地副本,而你希望原始數據保持不變。例如,如果你是一家銀行,你有一個函數向用戶顯示根據他們選擇的儲蓄計劃而產生的余額變化,你不希望在客戶選擇計劃之前更改他…

OpenAI在中國,申請GPT-6、GPT-7商標

根據最新商標信息顯示&#xff0c;OpenAI已經在中國提交了GPT-6和GPT-7的商標注冊信息&#xff0c;分類是科學儀器和網站服務兩大類。申請日期是今年的11月2日&#xff0c;目前處于審核狀態。 該申請由知識產權代理公司完成&#xff0c;但申請人的地址正是OpenAI在美國公司的地…

Echarts圖表title使用富文本

rich中有配置的話&#xff08;如a&#xff09;使用該樣式&#xff0c;沒有配置樣式的話&#xff08;如b&#xff09;使用外層textstyle的樣式&#xff0c;textstyle沒有樣式的話使用默認樣式 const option1 {tooltip: {trigger: "item",},title: {text: ["{a|1…

Java代碼審計之SpEL表達式注入漏洞分析

文章目錄 前言SpEL表達式基礎基礎用法安全風險案例演示 CVE-2022-22963漏洞簡述環境搭建反彈shell CVE漏洞調試分析本地搭建調試分析補丁分析 總結 前言 表達式注入是 Java 安全中一類常見的能夠注入命令并形成 RCE 的漏洞&#xff0c;而常見的表達式注入方式有 EL 表達式注入…

124.(leaflet篇)leaflet禁止地圖移動,縮放,雙擊

地圖之家總目錄(訂閱之前必須詳細了解該博客) 完整代碼工程包下載,運行如有問題,可“私信”博主。效果如下所示: 下面獻上完整代碼,代碼重要位置會做相應解釋 <!DOCTYPE html> <html>

深入探索HTTPS加密技術與新興安全趨勢:保衛隱私的未來之路

在前文中&#xff0c;我們了解了HTTPS加密協議的工作原理和應用場景。然而&#xff0c;隨著技術的不斷發展和網絡安全威脅的不斷演變&#xff0c;HTTPS加密技術也在不斷進化。在本篇博文中&#xff0c;我們將更深入地探討HTTPS加密技術&#xff0c;并介紹一些新興的安全趨勢&am…

css中的 box-sizing: border-box

box-sizing: border-box 是 CSS 中的一個盒子模型屬性&#xff0c;用于指定元素的盒子模型的計算方式。默認的盒子模型是 content-box&#xff0c;而使用 border-box 則表示元素的寬度和高度包括了元素的邊框和內邊距&#xff0c;而不僅僅是內容的寬度和高度。 在默認的 conte…

【Docker】使用docker-compose搭建django+vue工程文章

我們嘗試使用docker-compose編排一個后端基于django,前端基于vue,數據庫為postgresql并使用nginx進行反向代理的web工程。 工程準備 Docker 安裝Docker 安裝docker-compose django 在python3.7的環境下創建 修改settings.py文件 修改 將靜態文件收集路徑添加進 ,筆…

pip指定優先從豆瓣源下載包

對于 Unix/macOS 系統&#xff0c;使用以下命令&#xff1a; pip config set global.index-url https://pypi.douban.com/simple/ 對于 Windows 系統&#xff0c;打開命令提示符或PowerShell&#xff0c;并使用相同的命令&#xff1a; pip config set global.index-url http…

react re-render的解決方案

問題代碼 import {Dispatch, FC, SetStateAction, useState} from reactimport ./App.cssconst Child: FC<{ m: number, setM: Dispatch<SetStateAction<number>> }> (props) > {const {m, setM } propsreturn (<div><button onClick{() &…

阿里java社招一面

1、項目所負責的功能介紹&#xff1b;B用戶對A用戶的用餐評價進行評論以及B用戶對評論進行追評的話怎么設計數據庫結構&#xff1b;菜品好評度排行榜怎么實現的 2、clickhouse為什么快 3、線程池有哪幾種&#xff0c;分別說說定義和優缺點&#xff1b;多線程使用過程中要注意…

XUbuntu22.04之8款免費UML工具(一百九十七)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

前端知識筆記(四)———JQuery 自動刷新頁面但不閃爍的實現方法

在本文中&#xff0c;我們將介紹如何使用jQuery實現自動刷新頁面但不出現閃爍的效果。通常情況下&#xff0c;當我們需要自動刷新頁面時&#xff0c;使用簡單的location.reload()方法即可實現&#xff0c;但這會導致頁面在刷新時出現短暫的白屏或閃爍。為了解決這個問題&#x…

供應鏈管理痛點大解析!內附解決方案

供應鏈是指涉及產品或服務生產、運輸、分銷和最終交付給客戶的過程。 用一個汽車制造的例子來幫助大家理解&#xff1a; 原材料采購&#xff1a; 汽車制造商需要從供應商處采購制造汽車所需的原材料&#xff0c;例如金屬、橡膠、塑料和玻璃。生產制造&#xff1a;獲得原材料&…