日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747


MySQL InnoDB存儲引擎:行鎖的3種算法

行鎖的三種算法

InnoDB存儲引擎有3種行鎖的算法,其分別是:

  • Record Lock:單個行記錄上的范圍
  • Gap Lock:間隙鎖,鎖定一個范圍,但不包含記錄本身
  • Next-Key Lock:Gap Lock + Record Lock,鎖定一個范圍,并且鎖定記錄本身

Record Lock總是會鎖住索引記錄,如果InnoDB存儲引擎建立的時候沒有設置任何一個索引,這時InnoDB存儲引擎會使用隱式的主鍵來進行鎖定。

Next-Key Lock是結合了Gap Lock和Record Lock的一種鎖定算法,在Next-Key Lock算法下,innodb對于行的查詢都是采用這種鎖定算法。例如一個索引有9,11,13,20這4個值,那么該索引可能被Next-Key Locking的范圍為(左開右閉 ):(- &,9](9,11](13,20](20,+ &)

采用Next-Key Lock的鎖定技術稱為Next-Key Locking。這種設計的目的是為了解決幻讀(Phantom Problem)。利用這種鎖定技術,鎖定的不是單個值,而是一個范圍。

當查詢的索引含有唯一屬性時,innodb存儲引擎會對Next-Key Lock進行優化,將其降級為Record Lock,即鎖住索引記錄本身,而不再是范圍。對于唯一索引,其加上的是Record Lock,僅鎖住記錄本身。但也有特別情況,那就是唯一索引由多個列組成,而查詢僅是查找多個唯一索引列中的其中一個,那么加鎖的情況依然是Next-key lock。

DROP TABLE
IF EXISTS t;

CREATE TABLE t (a INT PRIMARY KEY);
INSERT INTO t
VALUES
(1),
(2),
(5);

 

MySQL InnoDB存儲引擎:行鎖的3種算法

 

表t中共有1、2、5三個值。在上面的例子中,在會話A中首先對a=5進行X鎖定。而由于a是主鍵且唯一,因此鎖定的僅是5這個值,而不是(2,5)這個范圍,這樣在會話B中插入值4而不會阻塞,可以立即插入并返回。即鎖定由Next-Key Lock算法降級為了Record Lock,從而提高應用的并發性。正如前面所介紹的,Next-Key降級為Record Lock僅在查詢的列是唯一索引的情況下。若是輔助索引,則情況會完全不同。同樣,首先根據如下代碼創建測試表Z:

CREATE TABLE Z (
a INT,
b INT,
PRIMARY KEY (a),
KEY (b)
);

INSERT INTO Z
VALUES
(1, 1),
(3, 1),
(5, 3),
(7, 6),
(10, 8);

表Z的列b是輔助索引,若在會話A中執行下面的SQL語句:

SELECT * FROM Z WHERE b=3 FOR UPDATE;

很明顯,這時SQL語句通過索引列b進行查詢,因此其使用傳統的Next-Key Locking技術加鎖,并且由于有兩個索引,其需要分別進行鎖定對于聚集索引,其僅對列a等于5的索引加上Record Lock。而對于輔助索引,其加上的是Next-Key Locking,鎖定的范圍是(1,3),特別需要注意的是,InnoDB存儲引擎會對輔助索引下一個鍵值加上gap lock,即還有一個輔助索引范圍為(3,6)的鎖。 因此,若在新會話B中運行下面的SQL語句,都會被阻塞:

SELECT * FROM Z WHERE a=5 LOCK IN SHARE MODE;
INSERT INTO Z SELECT 4,2;
INSERT INTO Z SELECT 6,5;

第一個SQL語句不能執行,因為在會話A中執行的SQL語句已經聚集索引中列a=5的值加上X鎖,因此執行會被阻塞。第二個SQL語句,主鍵插入4,沒有問題,但是插入的輔助索引值2在鎖定的范圍(1,3)中因此執行同樣會被阻塞。第三個SQL語句,插入的主鍵6沒有被鎖定,5也不在范圍(1,3)之間。但插入的值5在另一個鎖定范圍(3,6)中,故同樣需要等待。而下面的SQL語句,不會被阻塞,可以立即執行:

INSERT INTO Z SELECT 8,6;
INSERT INTO Z SEELCT 2,0;
INSERT INTO Z SELECT 6,7;

從上面的例子中可以看到,Gap Lock的作用是為了阻止多個事務將記錄插入到同一個范圍內,而這會導致Phantom Problem問題的產生。 例如在上面的例子中,會話A中用戶已經鎖定了b=3的記錄。若此時沒有Gap Lock鎖定(3,6),那么用戶可以插入索引b列為3的記錄,這會導致會話A中的用戶再次執行同樣查詢時會返回不同的記錄,導致Phantom Problem問題的產生。

用戶可以通過以下兩種方式來顯式地關閉Gap Lock:

  • 將事務的隔離級別設置為READ COMMITTED
  • 將參數innodb_locks_unsafe_for_binlog設置為1

在上述的配置下,除了外鍵約束和唯一性檢查依然需要的Gap Lock,其余情況僅使用Record Lock進行鎖定。但需要牢記的是,上述設置破壞了事務的隔離性,并且對于replication,可能會導致主從數據的不一致。此外,從性能上來看,READ COMMITTED也不會優于默認的事務隔離級別READ REPEATABLE。

在InnoDB存儲引擎中,對于INSERT的操作,其會檢查插入記錄的下一條記錄是否被鎖定,若已被鎖定,則不允許查詢。對于上面的例子,會話A已經鎖定了表z中b=3的記錄,即已經鎖定了(1,3)的范圍,這時若在其他會話中進行如下的插入同樣會導致阻塞:

INSERT INTO Z SELECT 2,2;

因為在輔助索引列b上插入值為2的記錄時,會監測到下一個記錄3已經被索引。而將插入修改為如下的值,可以立即執行:

INSERT INTO Z SELECT 2,0;

最后再次提醒的是,對于唯一鍵值的鎖定,Next-Key Lock降級為Record Lock僅存在于查詢所有的唯一索引一列。若唯一索引由多個列組成,而查詢是查找多個唯一索引列中的其中一個,那么查詢其實是range類型查詢,而不是point類型查詢故InnoDB存儲引擎依然使用Next-Key Lock進行鎖定。

最后再次提醒的是,對于唯一鍵值的鎖定,Next-Key Lock降級為Record Lock僅存在于查詢所有的唯一索引一列。若唯一索引由多個列組成,而查詢是查找多個唯一索引列中的其中一個,那么查詢其實是range類型查詢,而不是point類型查詢故InnoDB存儲引擎依然使用Next-Key Lock進行鎖定。

解決 Phantom Problem

在默認的事務隔離級別下,即REPEATABLE READ下,InnoDB存儲引擎采用Next-Key Locking機制來避免Phantom Problem (幻像問題)。這點可能不同于與其他的數據庫,如Oracle數據庫,因為其可能需要在SERIALIZABLE的事務隔離級別下才能解決 Phantom Problem。

Phantom Problem是指在同一事務下,連續執行兩次同樣的SQL語句可能導致不同的結果,第二次的SQL語句可能會返回之前不存在的行。

下面將演示這個例子,使用前一小節所創建的表t。表t由1、2、5這三個值組成:

DROP TABLE
IF EXISTS t;

CREATE TABLE t (a INT PRIMARY KEY);
INSERT INTO t
VALUES
(1),
(2),
(5);

若這時事務T1執行如下的SQL語句:

SELECT * FROM t WHERE a> 2 FOR UPDATE;

注意這時事務T1并沒有進行提交操作,上述應該返回5這個結果。若與此同時,另一個事務T2插入了 4這個值,并且數據庫允許該操作,那么事務T1再次執行上述SQL語句會得到結果4和5。這與第一次得到的結果不同,違反了事務的隔離性,即當前事務能夠看到其他事務的結果。其過程如表6-13所示:

 

MySQL InnoDB存儲引擎:行鎖的3種算法

 

InnoDB存儲引擎采用Next-Key Locking的算法避免Phantom Problem。對于上述的SQL語句SELECT * FROM t WHERE a>2 FOR UPDATE,其鎖住的不是5這單個值,而是對(2, +〇〇)這個范圍加了 X鎖。因此任何對于這個范圍的插入都是不被允許的,從而避免 Phantom Problem。

InnoDB存儲引擎默認的事務隔離級別是REPEATABLE READ,在該隔離級別下,其采用Next-Key Locking的方式來加鎖。而在事務隔離級別READ COMMITTED下,其僅采用Record Lock,因此在上述的示例中,會話A需要將事務的隔離級別設置為READ COMMITTED。

此外,用戶可以通過InnoDB存儲引擎的Next-Key Locking機制在應用層面實現唯一性的檢查。 例如:

SELECT * FROM table WHERE col=xxx LOCK IN SHARE MODE;
If not found any row:
# unique for insert value
INSERT INTO table VALUES (...);

如果用戶通過索引査詢一個值,并對該行加上一個SLock,那么即使査詢的值不在,其鎖定的也是一個范圍,因此若沒有返回任何行,那么新插人的值一定是唯一的。也許有讀者會有疑問,如果在進行第一步SELECT •••LOCK IN SHARE MODE操作時,有多個事務并發操作,那么這種唯一性檢査機制是否存在問題。其實并不會,因為這時會導致死鎖,只有一個事務的插人操作會成功,而其余的事務會拋出死鎖的錯誤,如表6-14所示。

 

MySQL InnoDB存儲引擎:行鎖的3種算法

 


 

分享到:
標簽:行鎖
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定