共計 2711 個字符,預計需要花費 7 分鐘才能閱讀完成。
這期內容當中丸趣 TV 小編將會給大家帶來有關 RR 模式下 NEXT-KEY LOCK 范圍到底有多大,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
我們知道 MYSQL NEXT-KEY LOCK 是用來防止幻讀,在 RR 模式下就有了用武之地
實際就是當前行鎖 + 前后的一個區間,但是這個區間到底有多大?
是簡單的一個輔助索引列上的閉區間嗎?
測試全部是在 RR 模式下 RC 模式不存在
建立測試表:
CREATE TABLE `test` (
`a` int(11) NOT NULL DEFAULT 0 ,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
插入幾行數據
mysql insert into test values(10,2);
Query OK, 1 row affected (0.01 sec)
mysql insert into test values(15,2);
Query OK, 1 row affected (0.02 sec)
mysql insert into test values(20,4);
Query OK, 1 row affected (0.01 sec)
mysql insert into test values(25,6);
Query OK, 1 row affected (0.02 sec)
mysql insert into test values(99,8);
Query OK, 1 row affected (0.00 sec)
mysql commit;
Query OK, 0 rows affected (0.00 sec)
mysql select * from test;
+—-+——+
| a | b |
+—-+——+
| 10 | 2 |
| 15 | 2 |
| 20 | 4 |
| 25 | 6 |
| 99 | 8 |
+—-+——+
5 rows in set (0.00 sec)
會話 A:
mysql begin;
Query OK, 0 rows affected (0.00 sec)
mysql select * from test where b=4 for update;
+—-+——+
| a | b |
+—-+——+
| 20 | 4 |
+—-+——+
1 row in set (0.00 sec)
會話 B:
mysql select * from test where b=2 for update;
+—-+——+
| a | b |
+—-+——+
| 10 | 2 |
| 15 | 2 |
+—-+——+
2 rows in set (0.00 sec)
mysql select * from test where b=6 for update;
+—-+——+
| a | b |
+—-+——+
| 25 | 6 |
+—-+——+
1 row in set (0.00 sec)
都沒有問題,那顯然這些列都沒加 X 鎖, 那是不是可以簡單的理解鎖定是
一個 2 - 6 的區間不包含 2 和 6 呢?
看下面的語句:
mysql insert into test values(16,2);
^CCtrl-C — sending KILL QUERY 3 to server …
Ctrl-C — query aborted.
ERROR 1317 (70100): Query execution was interrupted
mysql insert into test values(16,6);
^CCtrl-C — sending KILL QUERY 3 to server …
Ctrl-C — query aborted.
ERROR 1317 (70100): Query execution was interrupted
均鎖定了
但是
mysql insert into test values(14,2);
Query OK, 1 row affected (0.21 sec)
mysql insert into test values(26,6);
Query OK, 1 row affected (0.02 sec)
是可以執行的。
這也證明了我們剛才的結論是不正確的,我們分析一下
| 15 | 2 |
| 20 | 4 |
| 25 | 6 |
這是原始的記錄我們對 4 進行了 for update,為了更小的縮小范圍
實際上 INNODB 把鎖的方位定義到了
b 列 2 a 列(15 到正無窮) b 列 4 全部 b 列 6 a 列(負無窮到 25)
之間全部的范圍,這看起來好像不是一個連續的區間,但是如果理解 B + 樹索引
同時 INNODB 在處理相同的值的時候按照主鍵升序進行排列就出現了一個連續的
區間,我們來畫一下,假設葉子節點如下排列,
實際上這樣我們就能看出這樣一個范圍,如果我們插入的是
values(16,2)顯然在這個范圍內它應該插入在 2 15
和 4 20
之間,所以鎖定
values(16,6)顯然也在范圍,他應該插入到 4 20 和 6 25
之間,所以鎖定
values(14,2)顯然不在這個范圍,他應該在 2 10
2 15 之間插入,所以 OK
values(26,6)在 6 25 和 8 99
之間當然也可以。
如果要插入 (3,3) 顯然不行,因為首先是按照 key 排序的他肯定在這個范圍內。
最后我們得出我們的結論:
b 列 2 a 列(15 到正無窮)
b 列 4
全部
b 列 6 a 列(負無窮到 25)
這樣一個范圍的插入全部不允許,當然 2 15 6 25 本身不包含因為可以 for update.
其實這樣做也是為了最小化鎖定范圍提高并發,所以輔助索引上的 gap lock 不僅取決
于輔助索引列還取決于主鍵列的值,但是要注意這個鎖是在輔助索引上的,而不是
主鍵上。
還有一點需要提醒:
如果鎖定是邊界記錄如上圖的
b=2 for update
和
b=8 for update
那么鎖定的范圍將變大
b=2 for update 鎖定的是 b 列負無窮 到 b 列 4 a 列(負無窮到 20)
如圖:
這里將虛擬行 infimum 寫出來代表負無窮
b=8
for update 鎖定的是 b 列 6 a 列 (25 到正無窮) 到 b 列 正無窮
如圖:
這里將 supremum 虛擬行列出來代表正無窮
實際就是看圖就理解了
最后就是需要驗證:
驗證從 2 個方面
1、對輔助索引的頁中鏈表進行分析, 如果在輔助索引頁內的鏈表按照首先是 KEY 排序然后 KEY 相同的按照 PRIMARY KEY 排序那么基本就驗證了我們的說法
這個隨后可以補上
2、源碼查看,源碼過于龐大就是 B + 樹索引數據結構的建立,查找,插入,刪除都非常難看懂,如果要到我們需要的證據非常困難,以后盡力。
上述就是丸趣 TV 小編為大家分享的 RR 模式下 NEXT-KEY LOCK 范圍到底有多大了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注丸趣 TV 行業資訊頻道。