細說Mysql間隙鎖

1.什麼是間隙鎖?間隙鎖是怎樣產生的?

2.間隙鎖有什麼作用?

3.使用間隙鎖有什麼隱患?

一、間隙鎖的基本概念

1.什麼叫間隙鎖

當我們用範圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引項加鎖;對於鍵值在條件範圍內但不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是所謂的間隙鎖(NEXT-KEY)鎖。

2.間隙鎖的產生

上面的文字很抽象,現在舉個栗子,介紹間隙鎖是怎麼產生的:

假設有以下表t_student:(其中id爲PK,name爲非唯一索引)

id name sex address
1 zhaoyi 0 beijin
3 sunsan 1 shanghai
4 lisi 0 guangzhou
5 zhouwu 0 shenzhen
6 wuliu 1 hangzhou

這個時候我們發出一條這樣的加鎖sql語句:

select id,name from t_student where id > 0 and id < 5 for update;

這時候,我們命中的數據爲以下着色部分:

id name sex address
1 zhaoyi 0 beijin
3 sunsan 1 shanghai
4 lisi 0 guangzhou
5 zhouwu 0 shenzhen
6 wuliu 1 hangzhou

細心的朋友可能就會發現,這裏缺少了條id爲2的記錄,我們的重點就在這裏。

select ... for update這條語句,是會對數據記錄加鎖的,這裏因爲命中了索引,加的是行鎖。從數據記錄來看,這裏排它鎖鎖住數據是id爲1、3和4的這3條數據。

但是,看看前面我們的介紹——對於鍵值在條件範圍內但不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖。

好了,我們這裏,鍵值在條件範圍但是不存在的記錄,就是id爲2的記錄,這裏會對id爲2數據加上間隙鎖。假設這時候如果有id=2的記錄insert進來了,是要等到這個事務結束以後纔會執行的

二、間隙鎖的作用

總的來說,有2個作用:防止幻讀和防止數據誤刪/改

1.防止幻讀

假設有下面場景

時間 事務A 事務B
T1 select count(1) from t_student where id > 1;  
T2   insert into t_student values(2,'qianer',1,'nanjing');
T3   commit;
T4 select count(1) from t_student where id > 1;  
T5 commit;  

如果沒有間隙鎖,事務A在T1和T4讀到的結果是不一樣的,有了間隙鎖,讀的就是一樣的了

2.防止數據誤刪/改

這個作用比較重要,假設以下場景:

時間 事務A 事務B
T1 delete from t_student where id < 4;  
T2   insert into t_student values(2,'qianer',1,'nanjing');
T3   commit;
T4 commit;  

這種情況下,如果沒有間隙鎖,會出現的問題是:id爲2的記錄,剛加進去,就被刪除了,這種情況有時候對業務,是致命性的打擊。加了間隙鎖之後,由於insert語句要等待事務A執行完之後釋放鎖,避免了這種情況

三.使用間隙鎖的隱患

最大的隱患就是性能問題

前面提到,假設這時候如果有id=2的記錄insert進來了,是要等到這個事務結束以後纔會執行的,假設是這種場景  

時間 事務A 事務B
T1 select * from t_student where id>1 and id < 100 for update;  
T2   insert into t_student values(2,'qianer',1,'nanjing');
T3 update t_student set xxxx where id=xxx;  
T4 update t_student set xxxx where id=xxx;  
T5 update t_student set xxxx where id=xxx;  
T6  
T7 commit;  

這種情況,對插入的性能就有很大影響了,必須等到事務結束才能進行插入,性能大打折扣

更有甚者,如果間隙鎖出現死鎖的情況下,會更隱晦,更難定位

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章