參考:MySQL 加鎖處理分析。該文已經講的很詳盡了,也易懂,下面僅僅是我的作的總結。mysql
1、 背景
1.1 隔離級別
1.2 加鎖過程
逐條處理,逐條加鎖。sql
1.3 兩階段鎖2PL
1.4 gap鎖
gap鎖是間隙鎖,即相鄰兩條有效記錄間隙的鎖(鎖的是間隙),它是針對insert的,用來解決幻讀的發生。它會阻塞insert,但不會阻塞delete/update等(記錄原本也不存在)。session
RC與RR的重要區別就是幻讀。因此RR才須要引入gap鎖。post
2、加鎖組合分析
說加什麼鎖,首先要了解兩個前提:1)隔離級別;2)用到的索引。不一樣的隔離級別,不一樣的索引都會影響加鎖。優化
2.1 可提交讀RC
主鍵/惟一鍵 | 二級索引 | 無索引 | |
select | 無 | 無 | 無 |
insert | 行鎖 | 行鎖 | 行鎖 |
select...for update/update/delete | 行鎖 | 有效行的行鎖 | 全表鎖聚簇索引 |
2.2 可重複讀RR
主鍵/惟一鍵 | 二級索引 | 無索引 | |
select | 無 | 無 | 無 |
insert | 行鎖 | 行鎖 | 行鎖 |
select...for update/update/delete | 行鎖 | 有效行的行鎖+gap鎖 | 全表鎖聚簇索引 |
2.3 可序列化S
主鍵/惟一鍵 | 二級索引 | 無索引 | |
select(快照讀) | S | S | S |
其餘(當前讀) | X | X | X |
注意:無索引時,select...for update/update/delete是須要鎖全表的,但mysql_server能夠作優化,在逐條加鎖時,若是發現不是目標記錄,能夠釋放掉鎖。但這會違背2PL的原則。spa
2.4 結論
死鎖的發生與否,並不在於事務中有多少條SQL語句,死鎖的關鍵在於:兩個(或以上)的Session加鎖的順序不一致。server
加鎖過程是逐條處理,逐條加鎖(最終都反映在聚簇索引上)的。blog
- 主鍵,加在聚簇索引上;
- 二級索引,加在二級索引+聚簇索引上;
- 無索引,加在聚簇索引上。
因此若是兩個session用到不一樣的二級索引,那麼對聚簇索引的加鎖順序是不一致的,從而致使session間鎖的持有與競爭,很容易產生死鎖。索引