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