innodb中的鎖分爲S鎖,即共享鎖,另外一種爲X鎖,排它鎖,好比:html
共享鎖(S)mysql
select * from supplier where id=5 lock in share mode;
複製代碼
排他鎖(X)sql
select * from supplier where id=5 for update;
複製代碼
或者insert,delete,update語句,這都是排他鎖spa
兼容性3d
這兩種鎖的兼容以下:日誌
X | S | |
---|---|---|
X | N | N |
S | N | Y |
意向鎖code
能夠理解爲屬於S鎖和X鎖的父節點,即要獲取S鎖或者X鎖的話,必須先提早獲取意向鎖,即IS或者IX鎖,那綜合起來看下,這兩類鎖的兼容狀況以下cdn
X | S | IX | IS | |
---|---|---|---|---|
X | N | N | N | N |
S | N | Y | N | Y |
IX | N | N | Y | Y |
IS | N | Y | Y | Y |
隱式鎖htm
也是醉了,爲何要搞這麼多概念。。這種鎖,能夠認爲不衝突的時候不加鎖,這個時候的鎖就是隱式鎖,等遇到衝突了,該鎖會升級爲顯示鎖,仍是經過一個例子來講明吧:blog
事務1(其中age是普通索引)select * from test01 where age=21 for update;
複製代碼
咱們看到mysql中實際上是沒有找到鎖的:
事務2
insert into test01(id,name,age) values(8,'zzh',22);
複製代碼
這個時候因爲[21,23)有gap鎖,因此事務2會被阻塞住,這個時候再看mysql中的鎖記錄
能夠看到一開始事務1雖然使用的是...for update,可是因爲沒有衝突因此加的是隱式鎖,等到事務2開始致使有衝突存在,因此事務1的鎖改成現實鎖。具體在事務的不一樣隔離級別下,不一樣的場景加鎖分析,在hedecheng加鎖分析這篇文章已經講解的很是詳細了,這裏就再也不多說了。主要說下其餘狀況下總結的一些加鎖分析。
先來看官網對該鎖的解釋
咱們重點關注下紅色的區域:在遇到衝突的時候,會在該索引所在的位置加S鎖,而該共享鎖又很容易致使死鎖,官網中就有個例子來專門說明這種共享鎖致使的死鎖,即三個事務同事執行一條插入語句其中一個事務回滾致使死鎖: 咱們能夠簡單的把這種狀況模仿一遍: 事務1insert into test01(id,name,age)values(12,"zzh",33);
複製代碼
事務2
insert into test01(id,name,age)values(12,"zzh",33);
複製代碼
事務3
insert into test01(id,name,age)values(12,"zzh",33);
複製代碼
以下圖操做:
咱們看下Mysql中鎖的記錄 其中這個就印證了在乎向鎖衝突的時候,請求加的是S鎖,而後咱們回滾事務1事務1
rollback
複製代碼
這個時候咱們看到事務2成功了,事務3出現死鎖
咱們能夠從死鎖日誌中看到:
因此存在 事務2->事務3,事務3->事務2 死鎖發生
官網中還要另外一個相似的例子,這裏就很少作分析了,緣由相似。
下面咱們看下另外一種狀況:
事務1(事務id=2944)select * from test01 where age=21 for update;
複製代碼
事務2(事務id=2945)
insert into test01(id,name,age)values(2,"zzh",22);
複製代碼
事務3(事務id=2946)
select * from test01 where age=21 lock in share mode;
複製代碼
執行以下
mysql中鎖記錄 咱們能夠看到而後咱們提交事務1 事務1
commit;
複製代碼
咱們再從新執行事務1
事務1(事務id=29467)
select * from test01 where age=21 for update;
複製代碼
執行結果被阻塞:
咱們看下mysql中的鎖記錄: 能夠看到事務3擁有在age_idx的S鎖,阻塞了事務1要獲取的X鎖,那這個時候咱們提交事務3 事務3 commit; 咱們發現事務1還處於阻塞的狀態,看下mysql中的鎖記錄 這個時候明白了, 事務2雖然執行失敗,可是其因爲插入意向鎖衝突所加的S鎖並未釋放,因此會致使事務1還處於阻塞中。只有當咱們提交了事務2,事務1纔會真正執行。該語句加鎖分爲兩種狀況
select * from test01 where age=21 for update;
複製代碼
事務2
insert into test01(id,name,age)values(3,"zzh",22);
複製代碼
事務1
insert into test01(id,name,age)values(3,"zzh",100);
複製代碼
按如上順序執行結果:
咱們發現出現死鎖,事務2被mysql回滾以後事務1執行成功。咱們看下具體的死鎖日誌 經過死鎖日誌咱們能夠分析出來select * from test01 where age=21 for update;
複製代碼
事務2(事務id=29683)
select * from test01 where age=21 for update;
複製代碼
事務1
insert into test01(id,name,age)values(3,"zzh",22);
複製代碼
執行結果以下
能夠看到事務2
insert into test01(id,name,age)values(3,"zzh",22);
複製代碼
由上面的分析一樣得出事務2的等待有兩種狀況:
(1) 和事務1同樣,等待age=22的插入意向鎖,此時發現已經有事務1在等待該位置的插入意向鎖,那就等待該位置的S鎖
(2) 事務1雖然在age=22的插入意向鎖等待,可是id=3的插入意向鎖是加成功了,因此若是事務2在id=3這裏等待插入意向鎖的話,也會有衝突,那就等待該位置的S鎖
因此,有這兩種狀況都會致使事務出現死鎖,咱們具體看下死鎖日誌:
咱們看到:咱們上面有分析,事務2的等待應該是有兩種狀況,而出現這兩種狀況的可能就是事務2的這條語句
insert into test01(id,name,age)values(3,"zzh",22);
複製代碼
咱們瞭解到在記錄不存在的時候,若是對此記錄進行select...for update語句,該語句會對空位置加gap鎖,這個會比較危險,若是咱們的表用的是自增主鍵,而此時若是查詢一個不存在的記錄,那會把將來要插入的全部的空隙都加了gap鎖,會致使之後表中沒法在插入任何數據,這個極其危險。
本篇,咱們介紹了mysql中的鎖以及在實踐中可能遇到的一些死鎖,專門經過幾個demo集中分析了一下,對於加鎖的分析,在文中所提到的hedecheng的文章中,已經有很深的講解,因此本文並無對此總結。重點仍是經過一些實際中用到的例子進行實際的分析一下整個過程。重點是插入意向鎖和select...for update中的一些加鎖的分析。下一篇來專門介紹下mysql的MVCC機制