您好,登錄后才能下訂單哦!
這篇文章給大家介紹mysql中怎么實現 innodb鎖機制,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
InnoDB實現標準的行級鎖定,其中有兩種類型的鎖定:共享鎖(S)和排他鎖(X)。
1)共享鎖允許持有該鎖的事務讀取一行數據。
2)排他鎖允許持有該鎖的事務更新或刪除一行數據。
如果事務T1在行r上持有一個共享鎖(S),那么來自其他不同事務T2的對行r上的鎖的請求將按以下方式處理:
1)T2可以立即獲得行r的共享鎖,T1和T2都在r上保持了S鎖。
2)T2不能立即獲取到排它鎖。
如果事務T1在行r上持有排他(X)鎖,則不能立即批準某個不同事務T2對r上任一類型的鎖的請求。 相反,事務T2必須等待事務T1釋放對行r的鎖定。
InnoDB支持多種粒度鎖定,允許行鎖和表鎖并存。 例如,諸如LOCK TABLES ... WRITE之類的語句對指定表采用排他鎖(X鎖)。 但是有一個問題,如果一個事務對一張表的某條數據進行加鎖,這個時候如果有另外一個線程想要用LOCK TABLES進行鎖表,這時候數據庫要怎么知道哪張表的哪條數據被加了鎖,一張張表一條條數據去遍歷是不可行的。 為了使在多個粒度級別上的鎖定變得切實可行,InnoDB使用了意圖鎖定。 意向鎖是表級鎖,指示事務稍后對表中的行需要哪種類型的鎖(共享鎖或排他鎖)。
有兩種類型的意圖鎖:
1)意向共享鎖(IS)表示事務打算對表中的各個行設置共享鎖。
2)意向排他鎖(IX)表示事務打算對表中的各個行設置排他鎖。
例如,SELECT ... LOCK IN SHARE MODE設置IS鎖定,而SELECT ... FOR UPDATE設置IX鎖定。
意向鎖定協議如下:
1)事務在獲取表中某行的共享鎖之前,它必須首先獲取該表中的IS鎖或更強的鎖。
2)事務在獲取表中某行的排它鎖之前,它必須首先獲取該表中的IX鎖。
表級鎖類型的兼容性匯總在以下矩陣中:
X | IX | S | IS | |
X | 沖突 | 沖突 | 沖突 | 沖突 |
IX | 沖突 | 兼容 | 沖突 | 兼容 |
S | 沖突 | 沖突 | 兼容 | 兼容 |
IS | 沖突 | 兼容 | 兼容 | 兼容 |
如果一個鎖與現有鎖兼容,則將其授予請求的事務,但如果與現有鎖沖突,則不授予該鎖。 事務等待直到沖突的現有鎖被釋放。 如果鎖定請求與現有鎖定發生沖突,并且由于可能導致死鎖而無法被授予,則會發生錯誤。
意向鎖除了全表請求(例如LOCK TABLES ... WRITE)外,不阻止任何其他內容。 意圖鎖定的主要目的是表明某人正在鎖定表中的行或要鎖定表中的行。
在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監視器輸出中看起來類似于以下內容:
RECORD 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 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 ;;
間隙鎖是對索引記錄之間的間隙的鎖定,或者是對第一個或最后一個索引記錄之前的間隙的鎖定。例如:SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;防止其他事務將10到20之間的值插入到t.c1的列上,無論該列中是否已經存在這樣的值,因為該范圍內所有現有值之間的間隙是鎖定的。
間隙可能跨越單個索引值,多個索引值,甚至為空。間隙鎖是性能和并發性之間權衡的一部分,并且在某些事務隔離級別而非其他級別中使用。
對于查詢唯一行的語句時,鎖定行時使用唯一索引,不需要間隙鎖定。 (這不包括搜索條件僅包含多列唯一索引的某些列的情況;在這種情況下,會發生間隙鎖定。)例如,如果id列具有唯一索引,則以下語句僅使用 ID值為100的行的索引記錄鎖,其他會話是否在前面的間隙中插入行都沒有關系:
SELECT * FROM child WHERE id = 100;
如果id未建立索引或具有非唯一索引,則該語句會鎖定前面的間隙。
在這里還值得注意的是,可以通過不同的事務將沖突的鎖保持在間隙上。 例如,事務A可以在間隙上保留一個共享的間隙鎖(間隙S鎖),而事務B可以在同一間隙上保留排他的間隙鎖(間隙X鎖)。允許沖突的間隙鎖的原因是,如果從索引中清除記錄,則必須合并由不同事務保留在記錄上的間隙鎖。
InnoDB中的間隙鎖唯一目的是防止其他事務插入間隙。 間隙鎖可以共存。 一個事務進行的間隙鎖定不會阻止另一事務對相同的間隙進行間隙鎖定。 共享間隙鎖和排他間隙鎖之間沒有區別。 它們彼此不沖突,并且執行相同的功能。
間隙鎖定可以顯式禁用。 如果將事務隔離級別更改為READ COMMITTED或啟用innodb_locks_unsafe_for_binlog系統變量(現已棄用),則會發生這種情況。 在這種情況下,將禁用間隙鎖定進行搜索和索引掃描,并且僅將其用于外鍵約束檢查和重復鍵檢查。
Next-Key Lock是索引記錄上的記錄鎖定和索引記錄之前的間隙上的間隙鎖定的組合,即記錄鎖和間隙鎖的組合。
InnoDB執行行級鎖定的方式是,當它搜索或掃描表索引時,會在遇到的索引記錄上設置共享或互斥鎖。 因此,行級鎖實際上是索引記錄鎖。 索引記錄上的next-key lock也會影響該索引記錄之前的“間隙”。 即,next-key lock是索引記錄鎖定加上索引記錄之前的間隙上的間隙鎖定。 如果一個會話在索引中的記錄R上具有共享或排他鎖,則另一會話不能按照索引順序在R之前的間隙中插入新的索引記錄。
假設索引包含值10、11、13和20。此索引的可能的next-key lock涵蓋以下間隔,其中,圓括號表示排除區間端點,方括號表示包括端點:
(-∞, 10] (10, 11] (11, 13] (13, 20] (20, +∞)
對于最后一個間隔,next-key lock將間隙鎖定在索引中的最大值上方,此next-key lock僅鎖定最大索引值之后的間隙。
默認情況下,InnoDB以REPEATABLE READ事務隔離級別運行。 在這種情況下,InnoDB使用next-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 ;;
插入意圖鎖定是一種在行插入之前通過INSERT操作設置的間隙鎖定的類型。 此鎖發出插入意圖的信號是,在同一個索引間隙中,如果多個事務未插入間隙中的相同位置,則無需等待插入到同一索引間隙中的多個事務。 假設有索引記錄,其值分別為4和7。單獨的事務分別嘗試插入值5和6,在獲得插入行的排他鎖之前,每個事務都使用插入意圖鎖來鎖定4和7之間的間隙,但不要互相阻塞,因為行是無沖突的。
下面的示例演示了在獲得對插入記錄的排他鎖之前,使用插入意圖鎖的事務。 該示例涉及兩個客戶端A和B。
客戶端A創建一個包含兩個索引記錄(90和102)的表,然后啟動一個事務,該事務將排他鎖放置在ID大于100的索引記錄上。排他鎖在記錄102之前包括一個間隙鎖:
mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; mysql> INSERT INTO child (id) values (90),(102); mysql> START TRANSACTION; mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE; +-----+ | id | +-----+ | 102 | +-----+
客戶B開始交易以將記錄插入空白。 事務在等待獲得排他鎖的同時獲取插入意圖鎖。
mysql> START TRANSACTION; mysql> INSERT INTO child (id) VALUES (101);
插入意圖鎖定的事務數據在SHOW ENGINE INNODB STATUS和InnoDB監視器輸出中看起來類似于以下內容:
RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child` trx id 8731 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000066; asc f;; 1: len 6; hex 000000002215; asc " ;; 2: len 7; hex 9000000172011c; asc r ;;...
AUTO-INC鎖是一種特殊的表級鎖,由插入到具有AUTO_INCREMENT列的表中的事務獲取。 在最簡單的情況下,如果一個事務正在向表中插入值,則任何其他事務都必須等待自己在該表中進行插入,以便第一個事務插入的行接收連續的主鍵值。
innodb_autoinc_lock_mode配置選項控制用于自動增量鎖定的算法。 它使您可以選擇如何在可預測的自動增量值序列與插入操作的最大并發性之間進行權衡。
InnoDB支持包含空間列的列的空間索引,要處理涉及SPATIAL索引的操作的鎖定,next-key lock不能很好地支持REPEATABLE READ或SERIALIZABLE事務隔離級別。 多維數據中沒有絕對排序概念,因此不清楚哪個是next key。
為了支持具有SPATIAL索引的表的隔離級別,InnoDB使用predicate locks。 SPATIAL索引包含最小邊界矩形(MBR)值,因此InnoDB通過在用于查詢的MBR值上設置謂詞鎖定來強制對索引進行一致的讀取。 其他事務不能插入或修改將匹配查詢條件的行。
關于mysql中怎么實現 innodb鎖機制就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。