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...