mysql中的各種鎖把我搞糊涂啦~

大家好,我是公眾號:java小杰要加油歹颓, 今天來分享一個關(guān)于mysql的知識點(diǎn)——mysql中的鎖

  • 話不多說,直接開車

事務(wù)并發(fā)訪問情況

讀-讀 情況

  • 并發(fā)事務(wù)讀取相同的數(shù)據(jù),并不會對數(shù)據(jù)造成影響童芹,允許并發(fā)讀

寫-寫 情況

  • 多事務(wù)并發(fā)寫寫時會發(fā)生臟寫的情況涝滴,不過任何一個事務(wù)隔離級別都不允許此情況發(fā)生绣版,通過加鎖來杜絕臟寫

    臟寫

    • 事務(wù)T1 將數(shù)據(jù)改成了A,但是還未提交,可此時事務(wù)T2又將數(shù)據(jù)改成了B歼疮,覆蓋了事務(wù)T1的更改杂抽,T1更新丟失,這種情況叫做臟寫

    加鎖

    • 例如韩脏,現(xiàn)在事務(wù)T1,T2對這條記錄進(jìn)行并發(fā)更改缩麸,剛才說是隔離級別是通過加鎖來杜絕此臟寫的,流程如下
      image

      這個鎖結(jié)構(gòu)中有兩個比較關(guān)鍵的信息(其實(shí)還有很多信息赡矢,后面再聊)

    • trx信息:表示這個鎖結(jié)構(gòu)是和哪個事務(wù)所關(guān)聯(lián)的

    • is_waiting信息:表示當(dāng)前事務(wù)是否正在等待

Q: 能描述一下兩個事務(wù)并發(fā)修改同一條數(shù)據(jù)時杭朱,mysql這個鎖是怎么避免臟寫的嗎?

A :事務(wù)T1在更改這條數(shù)據(jù)前吹散,就先內(nèi)存中生成一把鎖與此數(shù)據(jù)相關(guān)聯(lián)(is_waiting為false,代表沒有等待)痕檬,然后咔咔一頓操作更改數(shù)據(jù),這個時候送浊,事務(wù)T2來了梦谜,發(fā)現(xiàn)此記錄已經(jīng)有一把鎖與之相關(guān)聯(lián)了(就是T1那一把鎖),然后就開始等待(is_waiting為true代表正在等待)袭景,事務(wù)T1更改完數(shù)據(jù)提交事務(wù)后唁桩,就會把此事務(wù)對應(yīng)的所結(jié)構(gòu)釋放掉,然后檢測一下還有沒有與此記錄相關(guān)聯(lián)的鎖耸棒,結(jié)果發(fā)現(xiàn)T2還在苦苦的等待荒澡,就把T2的鎖結(jié)構(gòu)的(is_waiting為false,代表沒有等待)然后把T2事務(wù)對應(yīng)的線程喚醒,T2獲取鎖成功繼續(xù)執(zhí)行与殃,總體流程如上单山。

讀-寫 /寫-讀 情況

在讀-寫 / 寫 -讀的情況下會出現(xiàn)臟讀碍现,不可重復(fù)讀,幻讀的現(xiàn)象米奸,不同的隔離級別可以避免不同的問題昼接,具體相關(guān)內(nèi)容可以看小杰的這篇文章 京東面試官問我:“聊聊MySql事務(wù),MVCC?”

不過貼心的我還是列出來了 注:√代表可能發(fā)生悴晰,×代表不可能發(fā)生

隔離級別 臟讀 不可重復(fù)讀 幻讀
讀未提交(read uncommitted RU)
讀提交(read committed RC) ×
可重復(fù)讀(repeatable read RR) × ×
串行化(serializable ) × × ×

但是 RR在某些程度上避免了幻讀的發(fā)生

怎么避免臟讀慢睡、不可重復(fù)讀、幻讀這些現(xiàn)象呢铡溪?其實(shí)有兩種方案

  • 方案一 :讀操作使用MVCC漂辐,寫操作進(jìn)行加鎖
  • mvcc里面最重要的莫過于ReadView了,它的存在保證了事務(wù)不可以讀取到未提交的事務(wù)所作的更改棕硫,避免了臟讀髓涯。
  • 在RC隔離級別下,每次select讀操作都會生成ReadView
  • 在RR隔離級別下哈扮,只有第一次select讀操作才會生成ReadView复凳,之后的select讀操作都復(fù)用這一個ReadView
  • 方案二:讀寫操作都用加鎖

某些業(yè)務(wù)場景不允許讀取舊記錄的值,每次讀取都要讀取最新的值灶泵。 例如銀行取款事務(wù)中育八,先把余額讀取出來,再對余額進(jìn)行操作赦邻。當(dāng)這個事務(wù)在讀取余額時髓棋,不允許其他事務(wù)對此余額進(jìn)行訪問讀取,直到取款事務(wù)結(jié)束后才可以訪問余額惶洲。所以在讀數(shù)據(jù)的時候也要加鎖

鎖分類

當(dāng)使用讀寫都加鎖這個方案來避免并發(fā)事務(wù)寫-寫按声、讀-寫寫-讀時而產(chǎn)生的臟讀恬吕,不可重復(fù)讀签则,幻讀現(xiàn)象時,那么這個鎖它就要做到铐料,讀讀時不相互影響渐裂,上面三種情況時要相互阻塞,這時鎖也分了好幾類钠惩,我們繼續(xù)往下看

鎖定讀

  • 共享鎖(Shared Lock):簡稱S鎖柒凉,在事務(wù)要讀取一條記錄時,需要先獲取該記錄的S鎖
  • 獨(dú)占鎖(Exclusive Lock):簡稱X鎖篓跛,也稱排他鎖膝捞,在事務(wù)要改動一條記錄時,需要先獲取該記錄的X鎖

他們之間兼容關(guān)系如下 √代表可以兼容愧沟,×代表不可兼容

兼容性 S鎖 X鎖
S鎖 ×
X鎖 × ×

事務(wù)T1獲取某記錄的S鎖后蔬咬,

  • 事務(wù)T2也可以獲取此記錄的S鎖鲤遥,(兼容)
  • 事務(wù)T2不可以獲取此記錄的X鎖,直到T1提交后將S鎖釋放 (不兼容)

事務(wù)T1獲取某記錄的X鎖后林艘,

  • 事務(wù)T2不可以獲取此記錄的S鎖盖奈,直到T1提交后將X鎖釋放 (不兼容)
  • 事務(wù)T2不可以獲取此記錄的X鎖,直到T1提交后將X鎖釋放 (不兼容)

鎖定讀語句

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`SELECT .. LOCK IN SHARE MODE # 對讀取的記錄添加S鎖

SELECT .. FOR UPDATE # 對讀取的記錄添加X鎖` </pre>

多粒度鎖

前面提到的鎖都是針對記錄的北启,其實(shí)一個事務(wù)也可以在表級進(jìn)行加鎖(S鎖卜朗、X鎖)

  • T1給表加了S鎖拔第,那么

    • T2可以繼續(xù)獲取此表的S鎖
    • T2可以繼續(xù)獲取此表中的某些記錄的S鎖
    • T2不可以繼續(xù)獲取此表的X鎖
    • T2不可以繼續(xù)獲取此表中的某些記錄的X鎖
  • T1給表加了X鎖咕村,那么

    • T2不可以繼續(xù)獲取此表的S鎖
    • T2不可以繼續(xù)獲取此表中的某些記錄的S鎖
    • T2不可以繼續(xù)獲取此表的X鎖
    • T2不可以繼續(xù)獲取此表中的某些記錄的X鎖

可是怎么可能平白無故的就給表加鎖呢,難道沒什么條件嗎蚊俺?答案是肯定有條件的

  • 若想給表加S鎖懈涛,得先確保表中記錄沒有X鎖
  • 若想給表加X鎖,得先確保表中記錄沒有X鎖和S鎖

但是這個怎么確保呢泳猬?難道要一行一行的遍歷表中的所有數(shù)據(jù)嗎批钠?當(dāng)然不是啦,聰明的大佬們想出了下面這兩把鎖

  • 意向共享鎖(Intention Shared Lock):簡稱IS鎖得封,當(dāng)事務(wù)準(zhǔn)備在某記錄上加S鎖時埋心,需要先在表級別加上一個IS鎖
  • 意向獨(dú)占鎖(Intention Exclusive Lock):簡稱IX鎖,當(dāng)事務(wù)準(zhǔn)備在某記錄上加X鎖時忙上,需要先在表級別加上一個IX鎖

讓我們來看下加上這兩把鎖之后的效果是什么樣子的

  • 當(dāng)想給記錄加S鎖時拷呆,先給表加一個IS鎖,然后再給記錄加S鎖
image
  • 當(dāng)想給記錄加X鎖時疫粥,先給表加IX鎖茬斧,然后再給記錄加X鎖
image

然后 經(jīng)過上面的操作之后

  • 如果想給表加S鎖,先看下表加沒加IX鎖梗逮,如果有的話项秉,則表明此表中的記錄有X鎖,則需要等到IX鎖釋放掉后才可以加S鎖
image
  • 如果想給表加X鎖慷彤,先看下表加沒加IS鎖或者IX鎖娄蔼,如果有的話,則表明此表中的記錄有S鎖或者X鎖底哗,則需要等到IS鎖或者IX鎖釋放掉后才可以加X鎖
image

這幾種鎖的兼容性如下表

兼容性 IS鎖(表級鎖) S鎖 IX鎖(表級鎖) X鎖
IS鎖(表級鎖) ×
S鎖 × ×
IX鎖(表級鎖) × ×
X鎖 × × × ×
  • IS贷屎、IX鎖都是表級鎖,他們可以共存艘虎。
  • 他們的提出僅僅是為了在之后加表級別的S鎖或者X鎖時可以快速判斷表中的記錄是否被上鎖唉侄,避免用遍歷的方式來查看一行一行的去查看而已

InnoDB中的行級鎖

Record Lock(記錄鎖)

  • 官方名字 LOCK_REC_NOT_GAP
  • 僅僅鎖住一條記錄
  • 有S型和X型之分

Gap Lock(間隙鎖)

  • 官方名字 LOCK_GAP
  • 給某記錄加此鎖后,阻塞數(shù)據(jù)在此記錄和上一個記錄的間隙插入野建,但是不鎖定此記錄
  • 有S型和X型之分属划,可是并沒有什么區(qū)別他們的作用是相同的恬叹,gap鎖的作用僅僅是為了防止插入幻影記錄而已,如果對一條記錄加了gap鎖(無論S/X型)并不會限制其他事務(wù)對這條記錄加Record Lock或者Gap Lock

Next-Key Lock(記錄鎖+間隙鎖)

  • 官方名字 LOCK_ORDINARY
  • 既可以鎖住某條記錄同眯,又可以組織其他事務(wù)在該記錄面前插入新記錄

Insert Intention Lock(插入意向鎖鎖)

  • 官方名字 LOCK_INSERT_INTENTION
  • 事務(wù)在插入記錄時绽昼,如果插入的地方加了gap鎖,那么此事務(wù)需要等待须蜗,此時此事務(wù)在等待時也需要生成一個鎖結(jié)構(gòu)硅确,就是插入意向鎖

鎖內(nèi)存結(jié)構(gòu)

  • 我們難道鎖一條記錄就要生成一個鎖結(jié)構(gòu)嗎?

當(dāng)然不是明肮!

一個鎖結(jié)構(gòu)

如果被加鎖的記錄符合下面四條狀態(tài)的話菱农,那么這些記錄的鎖則會合到一個鎖結(jié)構(gòu)

  • 在同一個事務(wù)中進(jìn)行加鎖操作
  • 被加鎖的記錄在同一個頁面中
  • 加鎖的類型是一樣的
  • 等待的狀態(tài)是一樣的
image

鎖結(jié)構(gòu)信息

然后我們再來依此看下這個所結(jié)構(gòu)每個部分的信息都是什么意思

image
  • 鎖所在的事務(wù)信息:無論是表級鎖還是行級鎖,一個鎖屬于一個事務(wù)柿估,這里記載著該鎖對應(yīng)的信息

  • 索引信息:對于行級鎖來說循未,需要記錄一下加鎖的記錄屬于哪個索引

  • 表鎖/行鎖信息:行級鎖

    • Space_ID:記錄所在的表空間 *** Page Number**:記錄所在的頁號
    • n_bits:一條記錄對應(yīng)著一個比特;一個頁面包含多條記錄秫舌,用不同的比特來區(qū)分到底是那一條記錄加了鎖,有個計算公式如下(公式中是取商)n_bits = (1+(n_recs+LOCK_PAGE_BITMAP_MARGIN)/ 8)x 8LOCK_PAGE_BITMAP_MARGIN是固定的值為64的妖,n_recs指當(dāng)前界面一共有多少條記錄(包含偽記錄以及在垃圾鏈表中的記錄),
  • type_mode:32比特的數(shù)

image
  • lock_mode(鎖模式):低4比特位表示

    • LOCK_AUTO_INC(十進(jìn)制的4):表示AUTO-INC鎖
    • LOCK_IS(十進(jìn)制的0):表示共享意向鎖足陨,IS鎖
    • LOCK_IX(十進(jìn)制的1):表示獨(dú)占意向鎖嫂粟,IX鎖
    • LOCK_S(十進(jìn)制的2):表示共享鎖,也就是S鎖
    • LOCK_X(十進(jìn)制的3):表示獨(dú)占鎖墨缘,也就是X鎖
  • lock_type(鎖類型):第5~8比特位表示

    • LOCK_TABLE(十進(jìn)制的1):當(dāng)?shù)?比特位設(shè)置為1時星虹,表示表級鎖
    • LOCK_REC(十進(jìn)制的32):當(dāng)?shù)?比特位設(shè)置為1時,表示行級鎖
  • rec_lock_type(行鎖的具體類型):其余的比特位表示

    • LOCK_ORDINARY(十進(jìn)制的0):表示next-key鎖

    • LOCK_GAP(十進(jìn)制的512):當(dāng)?shù)?0比特位是1時飒房,表示gap鎖

    • LOCK_REC_NOT_GAP(十進(jìn)制的1024):也就是當(dāng)?shù)?1比特設(shè)置為1時搁凸,表示Record Lock(記錄鎖)

    • LOCK_INSERT_INTENTION(十進(jìn)制的2048):也就是當(dāng)?shù)?2比特設(shè)置為1時,表示Insert Intention Lock(插入意向鎖)

    • LOCK_WAIT(十進(jìn)制的256):也就是當(dāng)

      • 第9比特設(shè)置為1時狠毯,表示is_waiting為true,即當(dāng)前事務(wù)獲取鎖失敗护糖,處于等待狀態(tài)
      • 第9比特設(shè)置為0時,表示is_waiting為false,即當(dāng)前事務(wù)獲取鎖成功
  • 其他信息:此文章不討論

  • 一堆比特位:此文章不討論

舉個例子

事務(wù)T1 要給user表中的記錄加鎖嚼松,假設(shè)這些記錄存儲在表空間號為20嫡良,頁號為21的頁面上,T1給id=1的記錄加S型Record Lock鎖献酗,假如當(dāng)前頁面一共有5條記錄(3條用戶記錄和2條偽記錄)

過程:先給表加IS鎖寝受,不過我們現(xiàn)在不關(guān)心,只關(guān)心行級鎖罕偎, 具體生成的所結(jié)構(gòu)如下圖所示

image

最后

  • 快過年啦很澄,小杰可能也需要休息一下下,因?yàn)樽罱贾芨m然上周有點(diǎn)事沒更,打臉)甩苛,周末完全沒有其余時間了
  • 感覺和朋友家人們聯(lián)系有點(diǎn)少了蹂楣,過年回家鞏固下感情和朋友們聊聊天吹吹牛逼,順便維護(hù)下峽谷的治安
  • 最后祝關(guān)注java小杰要加油的寶貝兒們
  • 脫單暴富事事順讯蒲,升職加薪牛哄哄痊土!

好文推薦

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腊凶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拴念,更是在濱河造成了極大的恐慌钧萍,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件政鼠,死亡現(xiàn)場離奇詭異风瘦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)公般,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門万搔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人官帘,你說我怎么就攤上這事瞬雹。” “怎么了刽虹?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵酗捌,是天一觀的道長。 經(jīng)常有香客問我,道長胖缤,這世上最難降的妖魔是什么馅巷? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮草姻,結(jié)果婚禮上钓猬,老公的妹妹穿的比我還像新娘。我一直安慰自己撩独,他們只是感情好敞曹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布寓调。 她就那樣靜靜地躺著饮戳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪澈段。 梳的紋絲不亂的頭發(fā)上剧劝,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天橄登,我揣著相機(jī)與錄音,去河邊找鬼讥此。 笑死拢锹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萄喳。 我是一名探鬼主播卒稳,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼他巨!你這毒婦竟也來了充坑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤染突,失蹤者是張志新(化名)和其女友劉穎捻爷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體份企,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡也榄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了薪棒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片手蝎。...
    茶點(diǎn)故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俐芯,靈堂內(nèi)的尸體忽然破棺而出棵介,到底是詐尸還是另有隱情,我是刑警寧澤吧史,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布邮辽,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏吨述。R本人自食惡果不足惜岩睁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揣云。 院中可真熱鬧捕儒,春花似錦、人聲如沸邓夕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焚刚。三九已至点弯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矿咕,已是汗流浹背抢肛。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碳柱,地道東北人捡絮。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像士聪,于是被迫代替她去往敵國和親锦援。 傳聞我的和親對象是個殘疾皇子猛蔽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容