mysql間隙鎖和行鎖

一 、基本概念

InnoDB支持幾種不同的行級鎖,MyISAM只支持表級鎖
行鎖(Record Lock): 對索引記錄加鎖。
間隙鎖(Gap Lock): 鎖住整個區(qū)間,包括:區(qū)間里具體的索引記錄,不存在的空閑空間(可以是兩個索引記錄之間,也可能是第一個索引記錄之前或最后一個索引記錄之后的空間)。
next-key鎖: 行鎖和間隙鎖組合起來。

注意:如果檢索條件不是索引的話會全表掃描,則是表級鎖,不是行級鎖

二、行鎖(Record Lock)

對主鍵或者唯一索引進行增刪改或顯示的加鎖,InnoDB會加行鎖,如:

-- 顯示的加鎖
select * from  people where id =3 for update;

update people set name='James' where id=3

注意:

  1. 正常的查詢語句使用的是共享鎖。
  2. 對于顯示的加鎖或增刪改操作,條件判斷必須是精確匹配(也就是=) ,不能用>,<,between或like等范圍查詢方式,因為這樣會使行鎖變成next-key Lock。
三、間隙鎖(Gap Lock)

官方文檔描述:Gap Lock的唯一目的就是阻止其他事務(wù)插入到間隙中。Gap Lock可以同時存在,不同的事務(wù)可以同時獲取相同的Gap Lock,并不會互相沖突。Gap Lock也是可以顯示的被禁止的,只要將事務(wù)的隔離級別降低到 READ COMMITTED。

對于間隙鎖,什么叫鎖住不存在的空閑空間,舉個例子:
一個表有id為1,2,3,5,6,9行數(shù)據(jù),執(zhí)行如下sql語句

select * from  people where id > 3 AND id <7 for update;

這是一個范圍檢索,InnoDB不僅會鎖住id為5和6兩行的數(shù)據(jù),也會鎖住id為4(雖然該行并不存在)的紀錄。

四、next-key Lock

官方文檔描述:Record Lock+Gap Lock,如果一個事務(wù)在記錄R上的某個索引有共享/互斥鎖,也會對其前面一個范圍加鎖

鎖定的區(qū)域
根據(jù)索引會形成一個個左開右閉的一個區(qū)間,根據(jù)查詢的條件其所在的區(qū)間,并且包括其后的區(qū)間。

這里給出一個people表

id name age
1 JAMES 37
2 OVEN 28
3 LOVE 34

如果age是索引的話,相關(guān)的區(qū)域有
(-無窮,28]
(28,34]
(34,37]
(37,+無窮)

如果執(zhí)行如下語句:

select * from  people where age =34 for update;

那么會鎖住(28,37]這么范圍

如果執(zhí)行如下語句:

select * from  people where age =33 for update;

那么會鎖住(28,34)這么范圍

間隙鎖的目的是為了防止幻讀,其主要通過兩個方面實現(xiàn)這個目的:
(1)防止間隙內(nèi)有新數(shù)據(jù)被插入
(2)防止已存在的數(shù)據(jù),更新成間隙內(nèi)的數(shù)據(jù)

innodb自動使用間隙鎖的條件
(1)必須在Repeatable Read級別下
(2)檢索條件必須有普通索引(沒有索引的話,mysql會全表掃描,那樣會鎖定整張表所有的記錄,包括不存在的記錄,此時其他事務(wù)不能修改不能刪除不能添加)

注意:這里的普通索引不包括主鍵索引和唯一索引,如果在這兩個索引下因為能精確檢索出結(jié)果,所以會使用Record Lock直接鎖定具體的行(范圍查詢除外)。

舉例: 對于表people

mysql> select * from people ;
+----+-------+
| id | name  |
+----+-------+
|  1 | JAMES |
|  2 | OVEN  |
|  3 | LOVE  |
+----+-------+

時間順序 session A session B
1 Begin;
2 Begin;
3 select * from people where name=“OVEN” for update ;(查詢到“OVEN”)
4 update people set name=“zph” where id=1; (此操作會被鎖住)

因為通過name索引執(zhí)行select …for update會將(1,“JAMES”)到(3,“LOVE”)之間的數(shù)據(jù)都鎖住,所以第4步會被鎖住。

但是如果通過id主鍵索引來檢索

時間順序 session A session B
1 Begin;
2 Begin;
3 select * from people where id=2 for update ;(查詢到“OVEN”)
4 update people set name=“zph” where id=1; (此操作會被執(zhí)行)

對于間隙鎖的許多例子可以看Mysql中的幾種行鎖(間隙鎖、next-key鎖)

這個博客中的圖片顯示不了,可以通過下面的url訪問
https://img-blog.csdnimg.cn/20200524231954401.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NzUxMzIw,size_16,color_FFFFFF,t_70

五 、快照讀和當前讀

快照讀: 通過MVCC實現(xiàn),該技術(shù)不僅可以保證innodb的可重復(fù)讀,而且可以防止幻讀。但是他讀取的數(shù)據(jù)雖然是一致的,但是數(shù)據(jù)是歷史數(shù)據(jù)。

簡單的select操作(不包括 select … lock in share mode, select … for update)

當前讀: 要做到保證數(shù)據(jù)是一致的,同時讀取的數(shù)據(jù)是最新的數(shù)據(jù)。innodb提供了next-key lock,即gap鎖與行鎖結(jié)合來實現(xiàn)。

select … lock in share mode

select … for update

insert

update

delete

總結(jié)

在可重復(fù)讀隔離級別下并不能避免幻讀,如果要避免的話需要使用Next-Key Lock。但是有了Next-Key Lock以后,會導(dǎo)致并發(fā)插入的時候產(chǎn)生等待,所以這時候需要進行相關(guān)的優(yōu)化。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容