InnoDB的next key lock 為什麼是左開右閉的?

時間 2021-06-20 07:21:48

1樓:

Next-Key Locks 的定義就是記錄鎖加上之前的 gap,所以是左開右閉

但是分析加鎖的時候,想著左開右閉也沒什麼意義,比如 RR 防止幻讀,需要加 Next-Key Locks(之前) 再加上記錄之後的 Gap,也就是記錄加鎖,記錄前後的gap(開區間)也加鎖。

你舉的例子,真的是(5,10]? 5 怎麼也要鎖定吧,懷疑是[5,10]才對

15.7.1 InnoDB LockingMySQL · 引擎分析 · InnoDB行鎖分析

2樓:李偉

前幾天剛才寫了一篇關於鎖的文章,裡面有提到gap鎖這一段

官方文件中定義:

A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.

所以我們可以觀察一下gap鎖是什麼樣的

建測試表如下並寫入資料:

CREATE TABLE `test_gap` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`age` int(11) DEFAULT NULL,

`name` varchar(10) DEFAULT NULL,

PRIMARY KEY (`id`),

KEY `ix_age` (`age`)

) ENGINE=InnoDB AUTO_INCREMENT=97 DEFAULT CHARSET=utf8;

觀察表上gap鎖的區間如下:

(-無窮,10] . (10,20] . (20,30] . (30,31] . (31,50] . (50,無窮]

首先說,上面區間描述好像沒有正面回答題主問題,我們先做動手測試了再說結論

begin;

select * from test_gap where age=31 for update;

觀察鎖的情況

我們觀察到鎖分別有如下幾個

表級別的IX鎖

age=31的rec x鎖

pk. id=80 的x鎖

age(30,50] 的gap鎖 --注意這裡沒有顯示30-31這一段

ok然後我們開始測試如下插入

begin;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into test_gap (age) values(29);

Query OK, 1 row affected (0.00 sec)

mysql> insert into test_gap (age) values(51);

Query OK, 1 row affected (0.00 sec)

很明顯,gap 之外的值成功插入了,這個沒有任何疑問

下面我們先不做gap內插入的測試,先來複習一下索引結構,我們知道MySQL中索引是 B+tree(請一定記住是b+tree,不要叫btree,這是兩種不同的資料結構,不要丟DBA同學的臉,哈哈)

b+tree的非葉子節點儲存的是二級索引的 key 值,資料節點存的是PK值,在這個基礎上,我們簡略畫出這顆樹(綠色值為PK):

然後我們觀察gap鎖的範圍,其實就是rec x鎖的上下邊界,是這裡畫圈的部分,那麼加這個鎖幹什麼用咱們就不解釋了

細心的同學這時候應該發現了(其實上面lock檢視裡已經看到PK值了),上下邊界裡不止包括了二級索引的值,還有Pk的值,大家可以想象一下,此時我插入什麼資料會在這個索引範圍內呢?

先考慮(id,age)的值分別如下時插入的結果:

(null,29)

(null,51)

(null,39)

(69,30)

(41,50)

(71,30)

(39,50)

到這裡,相信大家應該能看出來了,看上去都是二級索引的邊界值,但是在索引中物理位置是不一樣的,原因當然是因為PK咯,在gap邊界外的應該是可以插入的

所以我們測試一下

begin;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into test_gap (age) values(29);

Query OK, 1 row affected (0.00 sec)

mysql> insert into test_gap (age) values(51);

Query OK, 1 row affected (0.00 sec)

mysql> insert into test_gap (id,age) values(69,30);

Query OK, 1 row affected (0.00 sec)

mysql> insert into test_gap (id,age) values(41,50);

Query OK, 1 row affected (0.00 sec)

mysql> insert into test_gap (id,age) values(71,30);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into test_gap (id,age) values(39,50);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

完全和預期一致

到這裡,我們其實得出的結論是什麼?

那麼我提兩個問題

如果我插入(70,30)這個值在索引哪邊呢?

上面兩個問題當課後作業吧

3樓:葉金榮

InnoDB的next-key lock本身的設計方案就是左開右閉的,例如

select

*from

twherec2=

10for

update

;則鎖定的是 c2=10 這條記錄本身,以及其索引節點上 c2=10 前面的那個gap。

但在RR隔離級別中,為了避免發生幻讀,需要把所有可能插入 c2=10 這個值的位置都加上鎖,所以對 i=10 後面的gap也會加鎖。

例如,當前t表上的值有以下(id列是主鍵,c2列是普通索引,c3列無索引)

id c2 c3

1 1 1

2 3 2

10 5 10

15 15 15

20 10 20

30 20 20

那麼對於 c2 這個輔助索引,其索引記錄真實的值是下面這樣的(要包含id列值,innodb的特性決定的)

c2 id

1 1

3 2

5 10

10 20

15 15

20 30

那麼上面的加鎖請求

select

*from

twherec2=

10for

update

;真正要加鎖的範圍是 (5, 15),也就是說,除了 c2 = 10 這條記錄外,還要對 5~10、10~15這兩個gap也加上鎖,才能保證(RR隔離級別)事務期間,這兩個gap也不會插入c2=10的記錄,而導致發生幻讀。

innodb除Serializable的隔離級別意義何在?

陳廣勝 低隔離級別提供了效率和隔離性之間的乙個權衡。一般來說,越低的隔離級別,可以提供更低的延遲,更大的併發度,更高的吞吐量。但犧牲了隔離性,可能產生不一致異常。serializable避免了所有的異常,代價是讀寫阻塞,死鎖機會大,效率低。repeatable read和read committed...

InnoDB 的意向鎖有什麼作用?

離開地球表面 表級別的鎖有兩種,一種S鎖,一種X鎖,當我們想給乙個表加S或X鎖時,需要進行兩個判斷 1.表當前是否有其他級別鎖。2.表中的行資料是否有行鎖。1的情況很明顯,我們列舉一下2的情況。a.表加S鎖時,行鎖是S鎖,不衝突 b.表加S鎖時,行鎖是X鎖,衝突 c.表加X鎖時,行鎖是X鎖,衝突 d...

innodb中,事務中的資料在沒提交之前存放在哪?

innodb裡每行只有一條記錄,其它的都是undo log,所以沒有提交的資料就是那一行當前資料 髒讀就是直接讀這條記錄 其它讀會結合undo log獲取要讀的版本。 寇亞龍 傳統的UNIX或LINUX系統實現在核心中設有緩衝區快取記憶體或頁面快取記憶體,大多數磁碟I O都通過緩衝進行。在Mysql...