1. 程式人生 > >MySQL鎖和事務(一):InnoDB鎖(MySQL 官方文檔粗翻)

MySQL鎖和事務(一):InnoDB鎖(MySQL 官方文檔粗翻)

空間索引 系統 聚集索引 rds update 能夠 conf 沒有 得到

  // 寫在前面,實際上,數據庫加鎖的類型和範圍受到多種因素的影響,例如數據庫隔離等級,SQL語句,是否使用主鍵、索引等等。可以查看博文: http://www.cnblogs.com/zhaoyl/p/4121010.html 了解

  這一章節講述了InnoDB使用的鎖類型。

  • 共享鎖(S)和獨占鎖(X)
  • 意向鎖
  • 行鎖(record lock,不知道叫 記錄鎖是不是更好,百度了一下有人叫行鎖)
  • 間隙鎖(gap lock)
  • Next-Key鎖
  • 插入意向鎖
  • AUTO-INC(自增長)鎖
  • 空間鎖(Predicate Locks for Spatial Indexes)

 共享鎖和獨占鎖

  InnoDB實現了兩種標準的行級鎖,一種是共享鎖(S鎖),一種是獨占鎖(X鎖)。

  • 共享鎖允許事務讀取一條記錄。
  • 獨占鎖允許事務更新或者刪除一條記錄的鎖。

  如果一個事務 T1 擁有記錄 r 的共享鎖,另外一個事務 T2 想要對行 r 加鎖的請求會得到這樣的處理:

  • 如果 T2 想要加一個 S 鎖,那麽他能馬上獲得這個鎖。結果就是,T1 和 T2 同時擁有 r 的共享鎖。
  • T2 想要獲取的是 X 鎖,那麽這麽請求會被阻塞。

  如果一個事務 T1 擁有行 r 的 X 鎖,另外一個事務 無論想獲取 r 的什麽鎖都會被阻塞。事務 T2 必須要先等待 T1釋放 r 上面的S鎖。

意向鎖

  InnoDB 支持多粒度的鎖,允許行鎖和表鎖共存。為了支持多粒度的鎖,InnoDB引入了意向鎖。意向鎖是一個表級別的鎖,表明一個事務在之後(requires later)要獲取表中某些行的S鎖或X鎖。InnoDB中使用了兩種意向鎖(假設事務 T 已經向表 t 請求獲取對應的意向鎖)

  • 意向共享鎖(IS):事務 T 想要對表 t 中的一些行加上S鎖。
  • 意向排他鎖(IX):事務 T 想要對這些行加上X鎖。

  例如

SELECT ... LOCK IN SHARE MODE  

  設置了 IS 鎖,而

SELECT ... FOR UPDATE 

  設置了 IX 鎖。

  意向鎖協議(The intention locking protocol)如下所示:

  • 在一個事務獲取表 t 中某一行的 S鎖之前,他必須先獲取 IS鎖或者一個更重量級的鎖(X等)
  • 在一個事務獲取一行的 X鎖之前,他必須先獲取表 t的 IX鎖。

  這些規則可以總結為下面的圖表(橫向表示一個事務已經獲取了對應的鎖,縱向表示另外一個鎖想要獲取對應的鎖--這段話我自己加的):

X IX S IS
X   沖突   沖突   沖突   沖突  
IX 沖突   不沖突   沖突   不沖突  
S 沖突   沖突 不沖突   不沖突
IS 沖突   不沖突 不沖突   不沖突

  當行上的鎖與已經存在的鎖不沖突(兼容)時,可以被事務請求獲取,如果沖突話,就不行。事務必須等待沖突的鎖被釋放(才能獲取想要的鎖)。如果一個加鎖請求與已存在的鎖相互沖突,又一直得不到鎖,可能是發生了死鎖,或者出現了錯誤。

  因此,意向鎖不會阻塞除全表請求(例如,LOCK TABLES ...WAITE)之外其他請求。IX 和 IS鎖的主要目的是表明 某個請求(someone)已經鎖定了一行,或者將要鎖定一行記錄。

  意向鎖加鎖過程中記錄的事務數據類似於下面使用 SHOW ENGINE INNODB STATUS語句的 InnoDB 監控輸出:

  

TABLE LOCK TABLE test.t trx id 10080 lock mode IX

  

行鎖

  行鎖是一個加在索引記錄上的鎖,例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;會阻止其他任何事務插入,更新或者刪除那些 t.c1 = 10的記錄。

  行鎖總是在索引記錄上面加鎖,即使一張表沒有任何索引,在這種情況下,InnoDB會創建一個隱藏的聚集索引,然後使用這個索引來加上行鎖。

  行鎖加鎖過程中記錄的事務數據類似於下面使用 SHOW ENGINE INNODB STATUS語句的 InnoDB 監控輸出:

RECORDS LOCKS space id 58 page no 3 n bits 72 index PRIMARY of table test.t
trx id 10078 lock_mode X locks rec but not gap
Record lock ,heap on 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 4; hex 8000000a; asc  ;;
1: len 6; hex 00000000274f; asc  O;;
2: len 7; hex b60000019d0110; asc  ;;

間隙鎖

  間隙鎖是在索引記錄的間隙上加的鎖,或者在第一條索引記錄之前、最後一條索引記錄之後的區間上加的鎖。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 AND 20 FOR UPDATE; 阻止所有其他的事務 插入一條 t.c1 = 15的記錄,無論是否表中已經有一列的值是15(或者其他10-20之間的值),因為在這個範圍內的間隙都已經被加上了鎖。

  間隙可能只包括一個索引值,也可能包括多個索引值,甚至不包含任何索引值。

  使用唯一索引查找唯一一條記錄的語句是不會使用到間隙鎖的(這不包括查詢條件僅包含一個唯一索引的一部分的語句)。例如,假如 id 列有一個唯一索引,下面的語句只會使用行鎖加到 id = 100的行上面,而不會關心別的會話(session)是否在上述的間隙中插入數據。

SELECT * FROM child WHERE id = 100 ;  (感覺應該加一個 FOR UPDATE 或者 IN SHARE MODE 或者 數據庫隔離等級為 serializable)

  如果 id 列沒有索引或者不是唯一索引,這個語句會在上述的間隙上加鎖。

  值得提醒的是,不同的事務可以在間隙上擁有相互沖突的鎖。例如,事務 A 可以某一個間隙上的共享鎖(gap S-lock),同時另外一個事務可以在同一個間隙上擁有獨占鎖(gap X-lock)。原因在於如果一條索引記錄被刪除,其他事務擁有的對應間隙鎖必須進行歸並(強行翻譯,不太明白,原文:The reason conflicting gap locks are allowed is that if a record is purged from an index, the gap locks held on the record by different transactions must be merged.)

  間隙鎖是 ”完全禁止性的“(強行翻譯:purely inhibitive,看下文應該很好理解),意味著他們只會禁止其他的事務插入數據到間隙之中,而不會禁止別的事務獲取同一區間的間隙鎖。因此,間隙 X鎖和間隙 S鎖起到的效果是一樣的。

  間隙鎖可以被明確的禁止。你可以將事務隔離等級設置為 READ COMMITTED 或者啟用 innodb_locks_unsafe_for_binlog 系統變量(現在不建議使用 deprecated)。在這些情況下,間隙鎖在查詢和索引掃描中被禁用,只會在外鍵約束檢查和重復索引檢查時才會使用。

  使用READ COMMITTED 隔離等級和 啟用innodb_locks_unsafe_for_binlog系統變量也會造成一些額外的影響。在MySQL分析完 WHERE 條件之後,不匹配的行上面的行鎖會被釋放。對於 UPDATE 語句,InnoDB 進行一個”半一致性“讀,它會返回最新提交的版本(的行記錄)給MySQL,然後MySQL

  確定哪些行匹配了 UPDATE 的 WHERE 條件。

  

Next-Key Locks

  next-key 鎖是行鎖和在行鎖之前的間隙上的間隙鎖的聯合。

  InnoDB以這種形式實現行級鎖,當他查找或掃描表索引的時候,遇到匹配的的索引記錄,在上面加上對應的共享鎖或者獨占鎖。因此,行級鎖實際上是索引記錄鎖。next-key鎖同是會影響索引記錄之前的間隙。就是說,next-key lock就是一個索引記錄鎖加上一個在索引記錄之前的間隙上的間隙鎖。如果一個會話擁有記錄 R 的索引上面的一個共享鎖或獨占鎖,另外的會話無法立即在 R記錄索引順序之前的間隙上插入一條新的記錄。

  假設有一個索引包含值10,11,13和20。下列的間隔上都可能加上一個next-key lock,(符號表示不包含端點,]符號表示包含端點。

(negative infinity ,10]
(10,11]
(11,13]
(13,20]
(20,positive infinity)

  在最後一個區間中,next-key lock鎖定了索引中的最大值到一個“上確界”(一個虛假的索引記錄,他的值比所有索引記錄中所有值都要大)。上確界不是一個真實存在的索引記錄,所以,事實上,這個nex-key lock只是鎖定了最大索引值之後的區間。

  默認情況下,InnoDB啟用 REPEATABLE READ 事務隔離等級。在這種情況下,InnoDB在查找和掃描索引時會使用 nex-key lock,能避免 幻(影)行的出現。

  next-key lock 加鎖過程中記錄的事務數據類似於下面使用 SHOW ENGINE INNODB STATUS語句的 InnoDB 監控輸出:

  

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 00000000274f; asc O;;
2: len 7; hex b60000019d0110; asc ;;

插入意向鎖

  插入意向鎖

 

AUTO-INC Locks(自增長鎖)

  自增長鎖是特殊的表級鎖,被那些插入帶有AUTO_INCREMENT行的記錄到表中時占用。一個最簡單的例子,當一個事務在插入數據到表中時,其他任何的事務都等待,因此,第一個事務插入的行能夠擁有連續的主鍵值。

  innodb_autoinc_lock_mode配置選項控制了自增長鎖使用的算法。他允許你在可預測的自增長值和最大化並發插入操作之間進行權衡。

空間索引的斷言鎖

  InnoDB支持空間列上面的空間索引。

  在處理包括空間索引的相關鎖定操作時,next-key locking 在支持 REPEATABLE READ 和 SERIALIZABLE 事務隔離等級 上工作的不太好。在多維的數據上,沒有一個絕對的順序,因此,“下一個”鍵在哪裏並不是很清楚。

  為了支持帶有 空間索引的隔離等級,InnoDB使用了斷言鎖。空間索引包含了 最小外接矩陣(minimum bounding rectangle = MBR)值,所以InnoDB 強制對索引一致性讀的時候對查詢語句中使用的MBR值上設置一個斷言索引。其他的事務不能插入或者修改匹配這個查詢條件的行。

  

MySQL鎖和事務(一):InnoDB鎖(MySQL 官方文檔粗翻)