亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > MySQL > 正文

當Mysql行鎖遇到復合主鍵與多列索引詳解

2020-01-18 20:42:42
字體:
來源:轉載
供稿:網友

背景

今天在配合其他項目組做系統壓測,過程中出現了偶發的死鎖問題。分析代碼后發現有復合主鍵的update情況,更新復合主鍵表時只使用了一個字段更新,同時在事務內又有對該表的insert操作,結果出現了偶發的死鎖問題。

比如表t_lock_test中有兩個主鍵都為primary key(a,b) ,但是更新時卻通過update t_lock_test .. where a = ? ,然后該事務內又有insert into t_lock_test values(...)

InnoDB中的鎖算法是Next-Key Locking,很可能是因為這個點導致的死鎖,但是復合主鍵下會出發Next-Key Locking嗎,那多列聯合unique索引下又會觸發Next-Key Locking嗎,書上并沒有找到答案,得實際測試一下。

InnoDB中的鎖

鎖是數據庫系統區別于文件系統的一個關鍵特性。鎖機制用于管理對共享資源的并發訪[插圖]。InnoDB存儲引擎會在行級別上對表數據上鎖,這固然不錯。不過InnoDB存儲引擎也會在數據庫內部其他多個地方使用鎖,從而允許對多種不同資源提供并發訪問。例如,操作緩沖池中的LRU列表,刪除、添加、移動LRU列表中的元素,為了保證一致性,必須有鎖的介入。數據庫系統使用鎖是為了支持對共享資源進行并發訪問,提供數據的完整性和一致性。

由于使用鎖時基本都是在InnoDB存儲引擎下,所以跳過MyISAM,直接討論InnoDB。

鎖類型

InnoDB存儲引擎實現了如下兩種標準的行級鎖:

  • 共享鎖(S Lock),允許事務讀一行數據
  • 排它鎖(x lOCK),允許事務刪除或更新一條數據

如果一個事務T1已經獲得了r的共享鎖,那么另外的事務T2可以立即獲得行r的共享鎖,因為讀取并沒有改變r的數據,成這種情況為鎖兼容(Lock Compatible)。但若有其他的事務T3箱獲得行r的排它鎖,則比如等待T1、T2釋放行r上的共享鎖――這種情況稱為鎖不兼容。

排它鎖和共享鎖的兼容性:

/ X S
X 不兼容 不兼容
S 不兼容 兼容

InnoDB中對數據進行Update操作會產生行鎖,也可以顯示的添加行鎖(也就是平時所說的“悲觀鎖”)

select for update

鎖算法

InnoDB有3種行鎖的算法,其分別是:

Record Lock:單個行記錄上的鎖,就是字面意思的行鎖

Record Lock會鎖住索引記錄(注意這里說的是索引,因為InnoDB下主鍵索引即數據),ruguo InnoDB存儲引擎表在建立的時候沒有設置任何一個索引,那么這時對InnoDB存儲引擎會使用隱士的主鍵來進行鎖定。

Gap Lock:間隙鎖,鎖定一個范圍,但不包含記錄本身

Next-Key Lock:Gap Lock+Record Lock,鎖定一個范圍,并且鎖定記錄本身

Gap Lock和Next-Key Lock的鎖定區間劃分原則是一樣的。

例如一個索引有10/11/13和20這四個值,那么該索引被劃分的的區間為:

(-∞,10]
(10,11]
(11,13]
(13,20]
(20,+∞]

采用Next-Key Lock的鎖定技術稱為Next-Key Locking。其設計的目的是為了解決Phantom Problem,這將在下一小節中介紹。而利用這種鎖定技術,鎖定的不是單個值,而是一個范圍,是謂詞鎖(predict lock)的一種改進。

當查詢的索引含有唯一(unique)屬性時(主鍵索引,唯一索引)InnoDB存儲引擎會對Next-Key Lock優化,將其降級為Record Lock,即僅鎖住索引本身,不是范圍。

下面來看一個輔助索引(非唯一索引)下的鎖示例:

CREATE TABLE z ( a INT, b INT, PRIMARY KEY(a), KEY(b) );INSERT INTO z SELECT 1,1;INSERT INTO z SELECT 3,1;INSERT INTO z SELECT 5,3;INSERT INTO z SELECT 7,6;INSERT INTO z SELECT 10,8;

表z的列b是輔助索引,若果事務A中執行:

SELECT * FROM z WHERE b=3 FOR UPDATE

由于b列是輔助索引,所以此時會使用Next-Key Locking算法,鎖定的范圍是(1,3]。特別注意,InnoDB還會對輔助索引的下一個值加上Gap Lock,即還有一個輔助索引范圍為(3,6]的鎖。因此,若在新事務B中運行以下SQL,都會被阻塞:

1. SELECT * FROM z WHERE a = 5 LOCK IN SHARE MODE;//S鎖2. INSERT INTO z SELECT 4,2;3. INSERT INTO z SELECT 6,5;

第1個SQL不能執行,因為在事務A中執行的SQL已經對聚集索引中列a=5的值加上X鎖,因此執行會被阻塞。

第2個SQL,主鍵插入4,沒有問題,但是插入的輔助索引值2在鎖定的范圍(1,3]中,因此執行同樣會被阻塞。

第3個SQL,插入的主鍵6沒有被鎖定,5也不在范圍(1,3]之間。但插入的b列值5在另下一個Gap Lock范圍(3,6]中,故同樣需要等待。

而下面的SQL語句,由于不在Next-Key Lock和Gap Lock范圍內,不會被阻塞,可以立即執行:

INSERT INTO z SELECT 8,6;INSERT INTO z SELECT 2,0;INSERT INTO z SELECT 6,7;

從上面的例子可以發現,Gap Lock的作用是為了組織多個事務將數據插入到統一范圍內,這樣會導致幻讀問題(Phantom Problem)。例子中事務A已經鎖定了b=3的記錄。若此時沒有Gap Lock鎖定(3,6],其他事務就可以插入索引b列為3的記錄,這會導致事務A中的用戶再次執行同樣查詢會返回不同的記錄,即導致幻讀問題的產生。

用戶也可以通過以下兩種方式來顯示的關閉Gap Lock(但不推薦):

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

在InnoDB中,對于Insert的操作,會檢查插入記錄的下一條記錄是否被鎖定,若已經被鎖定,則不允許插入。對于上面的例子,事務A已經鎖定了表z中b=3的記錄,即已經鎖定了(1,3]的范圍,這時若在其他事務中執行如下插入也會導致阻塞:

INSERT INTO z SELECT 2,0

因為在輔助索引列b上插入值為2的記錄時,會監測到下一個記錄3已經被索引,修改b列值后,就可以執行了

INSERT INTO z SELECT 2,0

幻讀(Phantom Problem)

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

在默認的事務隔離級別(REPEATABLE READ)下,InnoDB存儲引擎采用Next―Key Locking機制來避免幻讀問題。

復(聯)合主鍵與鎖

上面的鎖機制介紹(摘自《Mysql技術內幕 InnoDB存儲引擎 第2版》),只是針對輔助索引和聚集索引,那么復合主鍵下行鎖的表現形式又是怎么樣呢?從書上并沒有找到答案,實際來測試一下。

首先創建一個復合主鍵的表

CREATE TABLE `composite_primary_lock_test` ( `id1` int(255) NOT NULL, `id2` int(255) NOT NULL, PRIMARY KEY (`id1`,`id2`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (10, 10);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (1, 8);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (3, 6);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (5, 6);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (3, 3);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (1, 1);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (5, 1);INSERT INTO `composite_primary_lock_test`(`id1`, `id2`) VALUES (7, 1);

事務A先來查詢id2=6的列,并添加行鎖

select * from composite_primary_lock_test where id2 = 6 lock in share mode

此時的鎖會降級到Record Lock嗎?事務B Update一條Next-Key Lock范圍內的數據(id1=1,id2=8)證明一下:

UPDATE `composite_primary_lock_test` SE WHERE `id1` = 1 AND `id2` = 8;

結果是UPDATE被阻塞了,那么再來試試加鎖時在where中把兩個主鍵都帶上:

select * from composite_primary_lock_test where id2 = 6 and id1 = 5 lock in share mode

執行UPDATE

UPDATE `composite_primary_lock_test` SE WHERE `id1` = 1 AND `id2` = 8;

結果是UPDATE沒有被阻塞

上面加鎖的id2=6的數據,不只1條,那么再試試對唯一的數據id2=8,只根據一個主鍵加鎖呢,會不會降級為行級鎖:

select * from composite_primary_lock_test where id2 = 8 lock in share mode;
UPDATE `composite_primary_lock_test` SE WHERE `id1` = 12 AND `id2` = 10;

結果也是被阻塞了,實驗證明:

復合主鍵下,如果加鎖時不帶上所有主鍵,InnoDB會使用Next-Key Locking算法,如果帶上所有主鍵,才會當作唯一索引處理,降級為Record Lock,只鎖當前記錄。

多列索引(聯合索引)與鎖

上面只驗證了復合主鍵下的鎖機制,那么多列索引呢,會不會和復合索引機制相同?多列unique索引呢?

新建一個測試表,并初始化數據

CREATE TABLE `multiple_idx_lock_test` ( `id` int(255) NOT NULL, `idx1` int(255) NOT NULL, `idx2` int(255) DEFAULT NULL, PRIMARY KEY (`id`,`idx1`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;ALTER TABLE `multiple_idx_lock_test` ADD UNIQUE INDEX `idx_multi`(`idx1`, `idx2`) USING BTREE;INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (1, 1, 1);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (5, 2, 2);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (7, 3, 3);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (4, 4, 4);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (2, 4, 5);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (3, 5, 5);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (8, 6, 5);INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (6, 6, 6);

事務A查詢增加S鎖,查詢時僅使用idx1列,并遵循最左原則:

select * from multiple_idx_lock_test where idx1 = 6 lock in share mode;

現在插入一條Next-Key Lock范圍內的數據:

INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (9, 6, 7);

結果是被阻塞了,再試一遍通過多列索引中所有字段來加鎖:

select * from multiple_idx_lock_test where idx1 = 6 and idx2 = 6 lock in share mode;

插入一條Next-Key Lock范圍內的數據:

INSERT INTO `multiple_idx_lock_test`(`id`, `idx1`, `idx2`) VALUES (9, 6, 7);

結果是沒有被阻塞

由此可見,當使用多列唯一索引時,加鎖需要明確要鎖定的行(即加鎖時使用索引的所有列),InnoDB才會認為該條記錄為唯一值,鎖才會降級為Record Lock。否則會使用Next-Key Lock算法,鎖住范圍內的數據。

總結

在使用Mysql中的鎖時要謹慎使用,尤其時更新/刪除數據時,盡量使用主鍵更新,如果在復合主鍵表下更新時,一定通過所有主鍵去更新,避免鎖范圍變大帶來的死鎖等問題。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對武林網的支持。

參考

《Mysql技術內幕 InnoDB存儲引擎 第2版》 - 姜承堯

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本久久久久久久久久久| 久热精品视频在线观看一区| 亚洲欧洲日产国产网站| 国产精品久久久久久av福利软件| 国产美女精品视频免费观看| 久久久久一本一区二区青青蜜月| 精品国产电影一区| 久久视频免费观看| 欧美性色视频在线| 久久全国免费视频| 在线精品国产成人综合| 久热爱精品视频线路一| 精品国产成人av| www国产精品com| 日韩精品在线免费播放| 美日韩丰满少妇在线观看| 日韩av在线免播放器| 97视频免费看| 国产精品你懂得| 欧美极品少妇全裸体| 国产日韩精品视频| 久久久久免费视频| 日本一区二区在线播放| xxxxxxxxx欧美| 九九九久久国产免费| 久久精品青青大伊人av| 欧美日韩亚洲视频| 亚洲国产精品久久91精品| 国产日韩欧美综合| 亚洲精品国产suv| 国产欧美 在线欧美| 亚洲欧美精品一区| 国产成人精品国内自产拍免费看| 国产日本欧美一区二区三区| 久久久国产精品x99av| 亚洲精品一区二区网址| 国产亚洲精品久久久优势| 欧美天天综合色影久久精品| 国产大片精品免费永久看nba| 亚洲专区国产精品| 超碰精品一区二区三区乱码| 91老司机精品视频| 国产精品99久久久久久白浆小说| 国产精品国模在线| 欧美日韩亚洲网| 欧美大胆a视频| 国产91精品在线播放| 亚洲免费av电影| 色偷偷av一区二区三区乱| 国产精品视频999| 国产精品一区二区性色av| 成人免费看片视频| 91精品中文在线| 欧美小视频在线观看| 亚洲国产精品99| 久久躁狠狠躁夜夜爽| 2025国产精品视频| 欧美午夜激情视频| 国产91精品高潮白浆喷水| 久久人人爽亚洲精品天堂| 欧美激情伊人电影| 国产精品a久久久久久| 亚洲欧美三级在线| 国产精品va在线播放我和闺蜜| 久久男人的天堂| 久热精品视频在线观看| 久久亚洲成人精品| 欧美在线观看www| 国产精品亚洲一区二区三区| 国产免费成人av| 久久av在线看| 亚洲欧美国产va在线影院| 岛国av一区二区在线在线观看| 欧美在线一级va免费观看| 日本中文字幕成人| 九九视频这里只有精品| 国产精品一区二区在线| 成人日韩在线电影| 亚洲精品xxx| 欧美激情综合亚洲一二区| 久久91亚洲精品中文字幕奶水| 成人中文字幕在线观看| 国产日韩欧美另类| 欧美专区第一页| 久久99热精品这里久久精品| 日韩久久午夜影院| 色播久久人人爽人人爽人人片视av| 91精品在线观| 国产精品女人久久久久久| 久久成人一区二区| 欧美精品免费看| 亚洲欧美激情精品一区二区| 91av视频在线播放| 久久国产精品电影| 亚洲国产成人av在线| 日本国产欧美一区二区三区| 欧美黄色成人网| 久久久久久999| 裸体女人亚洲精品一区| 亚洲精品国产拍免费91在线| 91大神福利视频在线| 亚洲国产成人精品一区二区| 欧美精品生活片| 欧洲成人免费视频| 久久久欧美一区二区| 亚洲一级一级97网| 国产精品丝袜久久久久久高清| 欧美国产欧美亚洲国产日韩mv天天看完整| 亚洲日本aⅴ片在线观看香蕉| 日韩视频永久免费观看| 亚洲电影在线看| 久久久伊人欧美| 国产精品久久久久久影视| 日韩欧美在线播放| 亚洲精品女av网站| 69av视频在线播放| 国产精品久久在线观看| 亚洲精品视频在线播放| 日韩激情av在线免费观看| 久久精品国产v日韩v亚洲| 美日韩精品免费观看视频| 国产欧美精品va在线观看| 在线观看日韩视频| 91老司机精品视频| 精品福利免费观看| 伊人激情综合网| 日韩免费av在线| 国产精品影片在线观看| 午夜精品久久久久久久久久久久久| 欧美成人午夜影院| 91精品国产乱码久久久久久蜜臀| 中文字幕欧美日韩va免费视频| 国产噜噜噜噜久久久久久久久| 美日韩在线视频| 日韩欧美在线第一页| 日韩国产欧美精品在线| 欧美激情乱人伦| 久久99热精品| 国产精品91久久| 国产亚洲精品久久久久动| 亚洲国产成人精品一区二区| 国产精品第2页| 国产亚洲精品久久久久久777| 国内外成人免费激情在线视频网站| 国产精品久久久久久久久粉嫩av| 91精品国产91久久久久福利| 日韩av观看网址| 一区二区成人精品| 精品二区三区线观看| 97在线视频一区| 国产精品91在线观看| 亚洲国产高清自拍| 91精品成人久久| 成人自拍性视频| 国产精品日韩久久久久| 欧美激情乱人伦一区| 久久影院资源网| 日韩中文字幕精品视频| 日韩美女视频免费在线观看| 热re91久久精品国99热蜜臀| 亚洲字幕在线观看| 亚洲天堂av高清| 91在线免费网站| 午夜精品一区二区三区在线视频|