首先你要知道:僅僅一篇文章是沒法全面講清楚明白mysql裏面的加鎖機制的!mysql
雖然網上有不少文章都號稱「理解mysql裏的加鎖機制看這一篇就夠了」,實際上都只是理論方面到位,工程實踐方面則都所不足。sql
本文針對工程實踐方面常常會碰到的一些關於鎖的問題進行剖析:設計
1.鎖的類型:code
常常碰到的主要是行鎖(record lock),間隙鎖(gap lock)和(next-key 鎖)。索引
舉個例子:隊列
select * from t where id=100 for update 或者 update t set name=? where id=100
上面兩種類型的sql語句的加鎖方式是一致的:事務
另外:若是查詢條件是大於或小於某個值,也即查詢的結果預期是一個區間時也會加區間鎖。class
咱們這能夠這樣來分析:date
2.共享和排他鎖:select
共享鎖就不講了,平時經常使用的主要是排他鎖,即一個會話對某行記錄加了排他鎖,則其餘會話就不能再得到這把鎖。
可是在mysql裏面:區間鎖相互之間是不互斥的,也就是不一樣會話能夠同時給同一個區間加鎖!
這樣一來,就會產生如下幾種狀況:
因此,要不要等待對方的鎖,就看你當前申請的鎖是否包含對方持有的行鎖,若是有則須要等待,不然不須要。
3.死鎖問題
通常來講,若是全部事務都保持一致的加鎖順序,則不容易產生死鎖。可是不容易產生,不表明不會產生,在一些特殊的狀況下仍是有可能碰到的!
這是由於在mysql中有這樣一個奇葩的機制:
一個會話在申請鎖的時候若是須要等待另外一方釋放鎖,則這個申請會進入鎖申請隊列,這時若是另外一方接下來須要申請的鎖與申請隊列中的鎖有衝突,則會產生死鎖!
好比有這樣兩個會話:
會話1:
select * from t where id=100 for update //id是惟一索引且記錄存在,這裏產生行鎖
會話2:
select * from t where id=100 for update //id是惟一索引且記錄存在,由於會話1持有行鎖,會話2只能等待,該申請會進入鎖申請隊列。
這時若是會話1再執行:
update t set name=xxx where id>90
此處查詢條件的結果是一個區間,因而產生了區間鎖,這個鎖與申請隊列中的會話2申請的鎖有衝突,就產生的死鎖!
是否是很奇葩?會話2尚未持有任何鎖,僅僅是申請了鎖而已,就產生了死鎖。mysql大概是這樣判斷的: