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

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

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前言

MySQL 作為使用范圍最廣的開(kāi)源關(guān)系型數(shù)據(jù)庫(kù),是每個(gè)后端開(kāi)發(fā)人員都繞不開(kāi)的一道坎。我在上一篇文章中也寫(xiě)了關(guān)于 MySQL 中的 MVCC 的細(xì)節(jié)及各個(gè)隔離級(jí)別如何使用 MVCC,有興趣的可以查看。

這一篇文章則是跟 MySQL 中的鎖有關(guān),鎖是在并發(fā)程序中最經(jīng)常使用的手段之一,但是鎖的濫用也會(huì)給程序的性能帶來(lái)極大的負(fù)擔(dān)。而我們平時(shí)使用 MySQL 做增刪改查操作的時(shí)候,感覺(jué)不到我們有在使用鎖,實(shí)際上是因?yàn)?MySQL 已經(jīng)為我們使用了相關(guān)的鎖。如果你想知道我們平時(shí)使用的 SQL 語(yǔ)句都使用了哪些鎖?都是怎么加鎖的?這些鎖的作用是什么?那么可以繼續(xù)往下看。

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

普通鎖

InnoDB 實(shí)現(xiàn)了標(biāo)準(zhǔn)行級(jí)鎖,而行級(jí)鎖有兩種類(lèi)型:

  • 共享鎖(shared lock,以下將會(huì)簡(jiǎn)稱(chēng)為 S 鎖):意在共享。也就是允許多個(gè)事務(wù)共同持有一個(gè)記錄的共享鎖,該鎖主要用于讀取操作。
  • 排他鎖(exclusive lock,以下將會(huì)簡(jiǎn)稱(chēng)為 X 鎖):意在排斥。只能允許一個(gè)事務(wù)持有一個(gè)記錄的排他鎖,該鎖主要用于更新和刪除操作。

如果你有了解過(guò) JAVA 中的 JUC 包,那么你就會(huì)發(fā)現(xiàn)這有點(diǎn)像 JUC 中的讀寫(xiě)鎖 ReentrantReadWriteLock。它們的目的都是為了提高讀取操作的并發(fā)性。

如果有一個(gè)事務(wù) T1 持有行 r 的 S 鎖,并且同時(shí)有另一個(gè)事務(wù) T2 想要獲取行 r 中的鎖,T2 獲取不同的鎖將會(huì)有如下的情況發(fā)生:

  1. 假如 T2 想要獲取行 r 的 S 鎖,那么 T2 將會(huì)立刻得到該鎖。
  2. 假如 T2 想要獲取行 r 的 X 鎖,那么 T2 則會(huì)被阻塞,直到 T1 釋放了行 r 的 S 鎖。

如果有一個(gè)事務(wù) T1 持有性 r 的 X 鎖,并且同時(shí)有另一個(gè)事務(wù) T2 想要獲取行 r 中的鎖,不管 T2 獲取什么鎖都會(huì)被阻塞。

X 鎖與 S 鎖的兼容性如下圖所示:

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

最左邊是持有的鎖,最上面是想要申請(qǐng)的鎖。從圖中可以看出,只要跟 X 鎖相關(guān)的,都會(huì)沖突,也就是會(huì)造成阻塞。

意向鎖

InnoDB 允許多種粒度的鎖共存,所以會(huì)有表鎖和行鎖共存的情況。為了讓多種粒度的鎖可以共存,InnoDB 使用了意向鎖。意向鎖是表級(jí)鎖,它是為了表明有一個(gè)事務(wù)正在持有鎖或者打算申請(qǐng)一個(gè)鎖。

意向鎖有兩種類(lèi)型:

  • 共享意向鎖(intention shared lock,以下簡(jiǎn)稱(chēng) IS):表示事務(wù)持有表中行的共享鎖或者打算獲取行的共享鎖。
  • 共享排他鎖(intention exclusive lock,以下簡(jiǎn)稱(chēng) IX):表示事務(wù)持有表中行的排他鎖或者打算獲取行的排他鎖。

IS 和 IX 只是為了表達(dá)出一種意圖,它們除了全表請(qǐng)求之外,不會(huì)阻塞任何操作。它們的主要目的只是為了表示持有一個(gè)行鎖,或者打算獲取行鎖。

意向鎖的使用規(guī)則如下:

  • 事務(wù)在獲取表中的共享行鎖時(shí),需要先獲取表中的 IS 鎖或者等級(jí)更高的鎖。
  • 事務(wù)在獲取表中的排他行鎖時(shí),需要先獲取表中的 IX 鎖。

這里有一個(gè)很重要的點(diǎn):就是只有獲取表中的行鎖時(shí),才會(huì)需要先申請(qǐng)意向鎖。 如果是執(zhí)行 ALTER TABLE 等需要鎖定整個(gè)表的語(yǔ)句,是不需要申請(qǐng)意向鎖的,可以直接去申請(qǐng)表級(jí) X 鎖。

表級(jí)別下的X鎖、S鎖、IS 鎖和 IX 鎖的兼容性如下:

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

注意:這里的 X 鎖、S 鎖說(shuō)的也是表級(jí)鎖,不要理所當(dāng)然的想成了行級(jí)鎖。

為什么會(huì)有意向鎖的出現(xiàn)呢?我們考慮如下場(chǎng)景(假設(shè)不存在意向鎖):

一個(gè)事務(wù) A 想要修改表 t 中的行 r,所以 A 獲取行 r 的 X 鎖,事r務(wù) A 現(xiàn)在持有一個(gè)行鎖。此時(shí),有一個(gè)事務(wù) B 想要使用 ALTER TABLE 語(yǔ)句修改表 t 的結(jié)構(gòu),該語(yǔ)句首先需要獲取表 t 的 X 鎖,但是此時(shí)事務(wù) B 并不知道表中是否有行被鎖住,所以它只能一行一行去遍歷,然后把遍歷的行也鎖住,直到發(fā)現(xiàn)表中沒(méi)有行在之前已經(jīng)被鎖住,現(xiàn)在它就可以修改表的結(jié)構(gòu)了。但是它發(fā)現(xiàn)表中已經(jīng)存在一些行被鎖住,那么它就不能修改表結(jié)構(gòu),需要等這些鎖都釋放。

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

這里有一個(gè)大問(wèn)題,最壞的情況下,需要遍歷所有的行才能知道是否有行被鎖住,這是非常消耗性能的,而意向鎖就可以解決這個(gè)問(wèn)題。我們現(xiàn)在再來(lái)考慮相同場(chǎng)景下,意向鎖如何解決這個(gè)問(wèn)題:

一個(gè)事務(wù) A 想要修改表 t 中的行 r,A 首先需要獲取表 t 的 IX 鎖,然后成功獲取 IX 鎖之后,再去申請(qǐng)行 r 的 X 鎖,申請(qǐng)成功之后,事務(wù) A 此時(shí)就持有兩個(gè)鎖,分別是表 t 的 IX 鎖和行 r 的 X 鎖。此時(shí),有一個(gè)事務(wù) B 想要使用 ALTER TABLE 語(yǔ)句修改表 t 的結(jié)構(gòu),該語(yǔ)句需要獲取表 t 的 X 鎖,事務(wù) B 可以查看表 t 上是否存在鎖來(lái)判斷表中的行是否被上鎖,當(dāng)發(fā)現(xiàn)表 t 上存在 IX 鎖,事務(wù) B 就會(huì)被阻塞,因?yàn)樗辣碇幸呀?jīng)有行被鎖定,所以無(wú)法申請(qǐng)到表 t 的 X 鎖。

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

我們看上面的兼容性表,也得知表級(jí)的 IX 鎖和表級(jí)的 X 鎖是沖突的,所以剛剛好對(duì)應(yīng)上這個(gè)場(chǎng)景。

記錄鎖

記錄鎖是對(duì)索引記錄的鎖定,換句話(huà)說(shuō)就是,記錄鎖只會(huì)鎖定索引。每一個(gè)表必定會(huì)有一個(gè)主鍵索引(用戶(hù)定義的主鍵、唯一索引、隱式生成),而該主鍵索引中的非葉子節(jié)點(diǎn)中的記錄就是使用該記錄鎖進(jìn)行鎖定。

假設(shè)執(zhí)行語(yǔ)句:select * from user where id = 10 for update;

如果 id 是 user 表中的主鍵,那么在主鍵索引中,id 為 10 的記錄就會(huì)被鎖定。并且其他事務(wù)想要更新、刪除此條記錄都會(huì)被阻塞,只有等該記錄中的記錄鎖被釋放之后,才可以執(zhí)行其他操作。

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

除了主鍵索引之外,InnoDB 中還會(huì)有二級(jí)索引。二級(jí)索引跟主鍵索引一樣,在使用二級(jí)索引作為查詢(xún)條件時(shí),會(huì)將符合條件的二級(jí)索引的記錄使用記錄鎖進(jìn)行鎖定,然后再回表將對(duì)應(yīng)的主鍵索引也使用記錄鎖進(jìn)行鎖定。

假設(shè)執(zhí)行語(yǔ)句:select * from user where name = 'c' for update;

如果 id 是 user 表中的主鍵,name 是 user 表中的二級(jí)索引。則會(huì)先將二級(jí)索引下的 name = ‘c’ 的索引鎖定,然后再進(jìn)行回表將主鍵索引為 9 的主鍵索引鎖定。

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

間隙鎖

間隙鎖(簡(jiǎn)稱(chēng)為 Gap)是對(duì)索引記錄之間的間隙的鎖定,或者是對(duì)第一條索引記錄之前的間隙和對(duì)最后一條記錄之后的間隙的鎖。間隙鎖是防止幻讀的主要手段之一,幻讀是同一個(gè)事務(wù)在不同的時(shí)間執(zhí)行相同的查詢(xún)語(yǔ)句,得出的結(jié)果集不同。那么間隙鎖是如何防止幻讀的呢?實(shí)際上就是通過(guò)鎖定指定的間隙,使得這些間隙無(wú)法插入新的記錄,從而防止了數(shù)據(jù)的增長(zhǎng)。

假設(shè)我們執(zhí)行此條語(yǔ)句:select * from user where id > 5 and id < 9 for update;

由于間隙鎖的存在,其他事務(wù)如果想要插入 id 在 5 和 9 之間的記錄是無(wú)法成功的,會(huì)被阻塞,直到間隙鎖釋放。比如想要插入 id 為 6 的記錄,就會(huì)阻塞,如下圖所示(省略部分無(wú)關(guān)的字段)。間隙鎖跨越的間隙可能為一個(gè)值、多個(gè)值、甚至為空值。

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

通過(guò)上圖我們可以知道:

  • (5, 7]:id 為 5 的索引記錄與 id 為 7 的索引記錄之間的間隙被間隙鎖鎖定了
  • (7, 9]:id 為 7 的索引記錄與 id 為 9 的索引記錄之間的間隙被間隙鎖鎖定了

因?yàn)檫@兩個(gè)間隙被間隙鎖鎖定了,所以在這兩個(gè)間隙之間的記錄是無(wú)法插入,只有等間隙鎖釋放之后才可以插入。我們還要注意到,id 為 7 的記錄是被記錄鎖鎖定的,所以在 id 為 7 的記錄上執(zhí)行更新、刪除操作時(shí)會(huì)被阻塞的。

我們上面還說(shuō)到,間隙鎖還在第一條記錄的前面和最后一條記錄的后面加鎖,我們來(lái)看看這是什么情況。

假設(shè)我們執(zhí)行此條語(yǔ)句:select * from user for update;

因?yàn)樵撜Z(yǔ)句沒(méi)有使用索引,所以會(huì)進(jìn)行全表掃描。將掃描到的每一條記錄都加上記錄鎖,并且將所有的間隙也加間隙鎖。最終的加鎖情況如下圖所示(省略部分無(wú)關(guān)的字段):

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

每個(gè)表中都會(huì)存在兩個(gè)隱式記錄:最小記錄(infimum),最大記錄(supermum)

我們通過(guò)上圖,可以得出鎖定的區(qū)間如下:

  • (-∞, 5]
  • (5, 7]
  • (7, 9]
  • (9, 10]
  • (10, 12]
  • (12, +∞)

并且所有的記錄都被記錄鎖鎖定。這個(gè)看起來(lái)就像是一個(gè)表鎖,因?yàn)閷?duì)該表的任何操作(快照讀除外),都會(huì)被阻塞。

但是,間隙鎖并不是在任何情況下都會(huì)使用,它在以下情況并不會(huì)使用:

  • 隔離級(jí)別為 RC、RU。
  • 使用唯一索引進(jìn)行等值比較獲取一條索引記錄。這是因?yàn)槲ㄒ凰饕M(jìn)行等值比較只能獲取一條記錄,不會(huì)出現(xiàn)多條記錄的情況,那么也就不會(huì)出現(xiàn)多次讀取出現(xiàn)不一致的情況。

間隙鎖的主要目的是阻止事務(wù)往間隙中插入記錄,并且間隙鎖之間是可以共存的,多個(gè)事務(wù)可以同時(shí)獲取得到相同間隙的鎖。共享間隙鎖和排他間隙鎖之間并沒(méi)有區(qū)別,它們是完全一樣的東西。

Next-Key 鎖

Next-Key 鎖并不是一個(gè)難以理解的東西,它本質(zhì)上就是索引記錄上的記錄鎖和索引記錄之間的間隙鎖的結(jié)合。

InnoDB 在查找和掃描表的時(shí)候,會(huì)將掃描到的記錄都加上記錄鎖,記錄鎖有可能是共享鎖或者是排他鎖。因此,行級(jí)鎖實(shí)際上是索引記錄鎖。

在間隙鎖的兩個(gè)例子中的第二個(gè)例子,它實(shí)際上就是 Next-Key 鎖,因?yàn)槊恳粋€(gè)括號(hào)括起來(lái)的內(nèi)存包括一個(gè)索引記錄鎖和一個(gè)間隙鎖,而 這完美符合 Next-Key 的定義。

在默認(rèn)的 REPEATABLE READ 隔離級(jí)別下,InnoDB 在查找和掃描索引時(shí),都會(huì)使用 Next-Key 鎖,以此來(lái)防止幻讀的發(fā)生。

插入意向鎖

插入意向鎖(簡(jiǎn)稱(chēng)為 II Gap)是一種特殊的間隙鎖,只有在插入記錄的時(shí)候才會(huì)使用,這個(gè)鎖表示插入的意向。它與上面說(shuō)到的表級(jí)意向鎖是完全不同的,插入意向鎖是屬于行級(jí)鎖,并且互相之間是兼容的,互不沖突,所以多個(gè)事務(wù)可以同時(shí)獲取到相同間隙的 II Gap 鎖。

官方示例:

假設(shè)有索引記錄,其值分別為4和7,單獨(dú)的事務(wù)分別嘗試插入值5和6,在獲得插入行的排他鎖之前,每個(gè)事務(wù)都使用插入意圖鎖來(lái)鎖定4和7之間的間隙,但不要互相阻塞,因?yàn)樾惺菬o(wú)沖突的。

插入意向鎖只會(huì)和間隙鎖和 Next-Key 鎖沖突。因?yàn)殚g隙鎖的主要作用是防止幻讀的發(fā)生,而在插入操作執(zhí)行前需要獲取到插入意向鎖,而插入意向鎖和間隙鎖之間是沖突的,可以阻塞插入操作,所以間隙鎖可以防止幻讀的發(fā)生。

AUTO-INC 鎖

AUTO-INC 鎖又稱(chēng)為自增鎖(簡(jiǎn)稱(chēng) AI 鎖)。它是特殊的表鎖,在插入數(shù)據(jù)到具有 AUTO_INCREMENT 列的表時(shí)使用。當(dāng)插入數(shù)據(jù)的表中有自增列時(shí),數(shù)據(jù)庫(kù)需要自動(dòng)生成自增值,在生成之前,它會(huì)先獲取到相關(guān)表的 AUTO-INC 鎖。其他事務(wù)的插入操作將會(huì)被阻塞,這樣可以保證自增值的唯一性。

AUTO-INC 鎖具有如下特點(diǎn):

  • 每一張表都具有它自己的 AUTO-INC 鎖,互相之間不兼容。
  • 不遵循二段鎖協(xié)議,它并不是在事務(wù)提交時(shí)釋放,而是在 insert 語(yǔ)句執(zhí)行完成之后就釋放,提高了并發(fā)插入的性能。
  • 自增值一旦分配了就會(huì)加一,即使回滾了,自增值也不會(huì)減一,而是繼續(xù)使用下一個(gè)值,所以自增值有可能不是連續(xù)的。

因?yàn)樵诓迦霑r(shí)會(huì)使用到該表鎖,所以必然會(huì)造成并發(fā)插入性能的下降。因此 InooDB 提供了一個(gè) innodb_autoinc_lock_mode 配置項(xiàng)用于控制自增鎖的算法,該配置項(xiàng)可以使用戶(hù)選擇如何在可預(yù)測(cè)的自動(dòng)增量值序列與插入操作的最大并發(fā)性之間進(jìn)行權(quán)衡。

該配置有三個(gè)可選項(xiàng):

  • 0:使用傳統(tǒng)的鎖定模式,并發(fā)性能最差。
  • 1:默認(rèn)采用的模式。
  • 2:并發(fā)性能最高,但是不能保證同一條 insert 語(yǔ)句內(nèi)的自增值是連續(xù)的。

想要了解更多關(guān)于此配置的內(nèi)容可以查看 MySQL 的這篇文檔。

總結(jié)

InnoDB 的四種行鎖的兼容性,如下表所示:

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

note: 第一列表示已經(jīng)持有的鎖,第一行表示要獲取的鎖。

從表中可以得出結(jié)論:

  • 插入意向鎖不影響其他事務(wù)獲取其他的鎖。
  • 插入意向鎖會(huì)受到 Gap 鎖和 Next-Key 鎖的影響。一個(gè)事務(wù)想要獲取指定間隙的插入意向鎖,那么該間隙中的 Gap 鎖和 Next-Key 鎖必須沒(méi)有被其他事務(wù)持有,否則,將會(huì)被阻塞。

如果,我們除去插入意向鎖的影響,那么兼容性表格如下:

快速解“鎖”MySQL,拿下這7把鑰匙,便能撬倒面試官

 

從表中我們可以得出以下結(jié)論:

  • 當(dāng)兩個(gè)事務(wù)的鎖都涉及到記錄鎖,那么將會(huì)沖突。
  • 間隙鎖與其他鎖(不包括插入意向鎖)都不會(huì)產(chǎn)生沖突。

作者:奮斗的小皇帝

原文:
https://juejin.im/post/5ef6d8355188252e5961a253

分享到:
標(biāo)簽:MySQL
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定