Record Lockssql
Gap Lockssession
AUTO-INC Lockscode
說明:本文中如無特殊說明,默認爲innodb引擎,事務隔離級別爲RR。事務
innodb 能夠經過兩種方式實現行級鎖定,即Shared(S) lock和Exclusive Lock (X)。如下簡稱爲S鎖和X鎖。資源
S鎖爲共享鎖,持有S鎖的事務能夠對該行進行讀取操做,且其餘session對該行不可修改。
X鎖爲排他鎖,持有X鎖的事務能夠對該行進行修改操做。
若是一條記錄被加了S鎖,那麼其餘事務仍能夠對其加S鎖。
若是一條記錄被加了X鎖,那麼其餘事務不能夠對其餘加S鎖或者X鎖。
下面一些狀況會加S鎖:
select ... lock in share mode , insert select ( select 中掃描到的記錄), update 連表更新中不進行更新的表 ,
IF EXISTS(select 中掃描到的記錄 ) ,使用外鍵時會對父鍵進行鎖定 ...
下面一些狀況會加X鎖:
select ... for update , update 中要更新的內容 ...
S鎖和X鎖對相同記錄的加鎖必定要保持合理的順序,不然會很容易形成死鎖。
另外,從支持資源併發的角度出發,寫各類語句必定要注意掃描的記錄數,不只僅是效率問題,更重要的是資源的利用最大化。
正確的認識X鎖和S鎖,對於資源的利用以及死鎖查找是很是重要的。
意向鎖主要是爲了支持多粒度鎖機制而存在的一種鎖,它不是由程序員去用程序控制,而是mysql本身來控制的。
舉個例子來講明mysql的意向鎖:
商場的一衛生間每晚都要進行鎖門,清潔工大爺天天鎖門前先進去挨個檢查下了五個隔斷是否有人,沒有人了方可把衛生間落鎖。
大爺以爲天天都要這樣檢查太麻煩,有沒有一種辦法我在門外都知道里面有沒有人?有一天他終於想到了一個辦法,他在門外掛了一個牌子,
正面寫着「沒人」,反面寫着「有人」,並且他給全部上衛生間的人兩條準則:
1 進入衛生間前,若是牌子是「沒人」,那麼必定要把牌子翻過來(「有人」)。
2 離開衛生間後,要檢查下5個隔斷,若是有人就直接離開,沒人了要把牌子翻過來(「沒人」)。
傳說全部人都這樣作了,而後老大爺晚上鎖門的時候直接看下門口的牌子就能夠決定鎖門與否,不再用本身進去檢查了。
在上面的例子中,假設衛生間是一個數據表,裏面的每個隔斷是一個數據行,那麼衛生間門外的牌子就是意向鎖。
Record lock是鎖在索引上的,即便沒有數據表沒有索引,mysql會鎖定聚簇索引。
gap鎖鎖住的是索引的間隙,主要爲了防止幻讀的發生。
例如:有一表名爲gap,裏面有字段c2,c2上有索引(非惟一索引),目前c2有值爲 2,4,7,10,幾個值。
如今開啓一個鏈接:
1 開始事務
2 更新c2值爲4的記錄 : update gap set remark = 'change' where c2 = 7;
(事務未提交)
如今開啓另一個鏈接:
1 開啓一個事務
2 此時,測試會發現
> insert gap(c2, remark) values(3,''); // success > insert gap(c2, remark) values(5,''); //block > insert gap(c2, remark) values(8,''); //block
能夠看出,在更新c2=7的記錄時,(4,7) 與 (7,10)之間的記錄都被鎖住了,不能進行插入。
如今,若是把c2的索引修改成惟一索引,再次執行上面的例子,結果又會不同,上面的三條記錄所有均可以插入。
所以,在惟一索引上加鎖是不會產生gap鎖的。在生產中,若是使用for update 進行記錄鎖定時,where後儘可能使用unique字段。
RR級別下,能夠經過設置系統變量innodb_locks_unsafe_for_binlog來使Gap lock 禁用(在查詢或者索引被掃描的時候)。
另外,若是刪除或者更新的記錄是經過惟一鍵進行掃描的時候,將不會有gap鎖產生。(所以,在進行對記錄的更改時,where後面最好用主鍵或者惟一鍵掃描,避免gap鎖)
next-key lock = record lock + gap lock;