http://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.htmlhtml
前置:檢索若是用不到索引,會掃描全表,並根據策略加鎖。因此,這就是咱們合理創建索引的原因。mysql
鎖定讀、Update、Delete,在處理sql過程當中, 通常會在每條掃描過的索引記錄上設置記錄鎖。語句中是否有where條件並無關係(會排除)。InnoDB不會記住實際上的Where條件,但他知道被掃描過的索引範圍。使用的鎖一般是next-key鎖,也會鎖住記錄以前的「gap」。Next-Key鎖不只僅鎖住掃描到的合法索引記錄,同時會阻塞插入gap間隙中,gap是指上一條合法索引記錄到當前掃描到的合法索引記錄的開區間。gap鎖能夠被顯示的禁止,致使next-key不會被使用。sql
事物的隔離級別一樣會影響使用什麼鎖。數據庫
若是一個二級索引被用來掃描,且索引記錄(二級索引,非惟一索引)將要加排他鎖,InnoDB會檢索相對應的聚簇索引記錄,並鎖住。併發
聚簇索引(clustered index)
1) 有主鍵時,根據主鍵建立聚簇索引
2) 沒有主鍵時,會用一個惟一且不爲空的索引列作爲主鍵,成爲此表的聚簇索引
3) 若是以上兩個都不知足那innodb本身建立一個虛擬的彙集索引
輔助索引(secondary index)
非聚簇索引都是輔助索引,像複合索引、前綴索引、惟一索引高併發
若是沒有合適的索引使用,MySQL會掃面整張表,來處理語句,這樣表中的每一行都會被鎖住(合理創建索引,提升併發效率)。性能
對於 SELECT ... FOR UPDATE
or SELECT ... LOCK IN SHARE MODE,掃描到的行都會鎖住,而且指望在有些row不會加入結果集中(例如不知足Where條件)釋放這些行的鎖。注:其實掃描了全表,只不過在掃描完成以後,判斷Where條件時不知足,則會釋放鎖。
然而對於某些狀況下,不會當即釋放行鎖,由於在查詢執行期間一個結果行和他的原始來源之間的關係可能已經丟失,例如Union,從表中掃描行,在計算他們是否加入結果集以前,這些行可能被插入臨時表中。此時,臨時表中的行和原始表中的行的關係已經丟失,原始表中的行不會解鎖知道查詢執行完成。spa
InnoDB按照以下設置具體的鎖:code
SELECT ... FROM 是一個一致性非鎖定讀,讀取數據庫的快照,不會加鎖,除非隔離級別爲S。對於S隔離級別,檢索結果集在索引記錄項上使用共享鎖且是next-key鎖。可是,當惟一肯定記錄時,next-key鎖會降級爲記錄鎖。
SELECT ... FROM ... LOCK IN SHARE MODE 在檢索到的全部索引記錄上設置共享鎖且是next-key鎖。可是,當惟一肯定記錄時,next-key鎖會降級爲記錄鎖。
SELECT ... FROM ... FOR UPDATE
在檢索到的每條記錄上的每個記錄上加排他鎖且是next-key鎖。可是,當惟一肯定記錄時,next-key鎖會降級爲記錄鎖。對索引記錄加的排他鎖阻塞共享鎖和某些隔離級別的操做讀。一致性非鎖定讀,會忽略任何鎖。UPDATE ... WHERE ...
在檢索到的每條記錄上的每個記錄上加排他鎖且是next-key鎖。可是,當惟一肯定記錄時,next-key鎖會降級爲記錄鎖。DELETE FROM ... WHERE ... 在檢索到的每條記錄上的每個記錄上加排他鎖且是next-key鎖。可是,當惟一肯定記錄時,next-key鎖會降級爲記錄鎖。
INSERT 設置一個排它鎖在插入的行上,這是一個記錄鎖,不是next-key,就是說沒有gap鎖,不會阻止其餘事物插入被插記錄以前的gap中。
在插入以前,一種叫插入意向鎖的gap類型鎖,被設置,這個鎖表示對事物插入同一個gap中時,不須要相互等待,只要他們不是插入gap中相同的位置。htm
設置插入操做的排他鎖以前,現貨去gap的插入意向鎖,倆個事物能夠在同一個gap(重疊也能夠)加插入意向鎖不會阻塞。
若是有重複衝突,一個共享鎖在重複的索引記錄上設置。共享鎖的使用可能致使死鎖:當多個會話插入相同的行時,若是有某個會話已經持有了X鎖,此時會致使死鎖。舉個例子:若是有某個會話刪除該行,另外倆個插入行,則會死鎖。
Session 1:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 2:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 3:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 1:
ROLLBACK;
上述狀況是會話1已經獲取了x鎖在r行上,會話2和4都會引發重複鍵衝突,倆個會話都轉而去請求r行共享鎖,當會話1回滾時,它釋放他的排它鎖,會話2和3的共享鎖請求被授予,此時,會話2和3死鎖:沒有任何一個會獲取排它鎖,由於他們都持有了共享鎖。
Session 1:
START TRANSACTION; DELETE FROM t1 WHERE i = 1;Session 2:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 3:
START TRANSACTION; INSERT INTO t1 VALUES(1);Session 1:
COMMIT;
上述狀況和第一種相似。
INSERT ... ON DUPLICATE KEY UPDATE 不一樣與簡單的Insert,當重複值衝突時,加的鎖是一個排它next-key鎖而不是一個共享鎖-記錄鎖。
REPLACE 若是在惟一key上沒有衝突,像INSERT同樣加鎖。夠則像INSERT ... ON DUPLICATE KEY UPDATE同樣
innodb_locks_unsafe_for_binlog
(此時不能是隔離級別S),InnoDB在S表上是一致性非鎖定讀(不加鎖)。不然,InnoDB會設置共享的next-key鎖到從S表檢索結果中的行。 CREATE TABLE ... SELECT ...
執行 SELECT使用共享的next-key鎖,或者一致性非鎖定讀,就像
INSERT ... SELECT
.同樣.
當一個SELECT在相似REPLACE INTO t SELECT ... FROM s WHERE ...
or UPDATE t ... WHERE col IN (SELECT ... FROM s ...)的結果中,InnoDB設置共享且next-key鎖在表S上的行上。
LOCK TABLES 設置表級鎖