1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 4701字,需瀏覽 10分鐘

         ·

        2021-02-24 18:57

        大家好,我是公眾號(hào):java小杰要加油, 今天來(lái)分享一個(gè)關(guān)于mysql的知識(shí)點(diǎn)——mysql中的鎖

        • 話不多說(shuō),直接開(kāi)車

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

        讀-讀 情況

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

        寫-寫 情況

        • 多事務(wù)并發(fā)寫寫時(shí)會(huì)發(fā)生臟寫的情況,不過(guò)任何一個(gè)事務(wù)隔離級(jí)別都不允許此情況發(fā)生,通過(guò)加鎖來(lái)杜絕臟寫
        ? ? ? 臟寫
        • 事務(wù)T1 將數(shù)據(jù)改成了A,但是還未提交,可此時(shí)事務(wù)T2又將數(shù)據(jù)改成了B,覆蓋了事務(wù)T1的更改,T1更新丟失,這種情況叫做臟寫

          加鎖

          • 例如,現(xiàn)在事務(wù)T1,T2對(duì)這條記錄進(jìn)行并發(fā)更改,剛才說(shuō)是隔離級(jí)別是通過(guò)加鎖來(lái)杜絕此臟寫的,流程如下這個(gè)鎖結(jié)構(gòu)中有兩個(gè)比較關(guān)鍵的信息(其實(shí)還有很多信息,后面再聊)
          • trx信息:表示這個(gè)鎖結(jié)構(gòu)是和哪個(gè)事務(wù)所關(guān)聯(lián)的
          • is_waiting信息:表示當(dāng)前事務(wù)是否正在等待
          • 事務(wù)T1 將數(shù)據(jù)改成了A,但是還未提交,可此時(shí)事務(wù)T2又將數(shù)據(jù)改成了B,覆蓋了事務(wù)T1的更改,T1更新丟失,這種情況叫做臟寫

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

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

        讀-寫 /寫-讀 ?情況

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

        不過(guò)貼心的我還是列出來(lái)了 注:√代表可能發(fā)生,×代表不可能發(fā)生

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

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

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

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

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

        鎖分類

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

        鎖定讀

        • 共享鎖(Shared Lock):簡(jiǎn)稱S鎖,在事務(wù)要讀取一條記錄時(shí),需要先獲取該記錄的S鎖
        • 獨(dú)占鎖(Exclusive Lock):簡(jiǎn)稱X鎖,也稱排他鎖,在事務(wù)要改動(dòng)一條記錄時(shí),需要先獲取該記錄的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鎖釋放 (不兼容)

        鎖定讀語(yǔ)句

        SELECT?..?LOCK?IN?SHARE?MODE???#?對(duì)讀取的記錄添加S鎖

        SELECT?..?FOR?UPDATE?#?對(duì)讀取的記錄添加X(jué)鎖

        多粒度鎖

        前面提到的鎖都是針對(duì)記錄的,其實(shí)一個(gè)事務(wù)也可以在表級(jí)進(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鎖

        可是怎么可能平白無(wú)故的就給表加鎖呢,難道沒(méi)什么條件嗎?答案是肯定有條件的

        • 若想給表加S鎖,得先確保表中記錄沒(méi)有X鎖
        • 若想給表加X(jué)鎖,得先確保表中記錄沒(méi)有X鎖和S鎖

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

        • 意向共享鎖(Intention Shared Lock):簡(jiǎn)稱IS鎖,當(dāng)事務(wù)準(zhǔn)備在某記錄上加S鎖時(shí),需要先在表級(jí)別加上一個(gè)IS鎖
        • 意向獨(dú)占鎖(Intention Exclusive Lock):簡(jiǎn)稱IX鎖,當(dāng)事務(wù)準(zhǔn)備在某記錄上加X(jué)鎖時(shí),需要先在表級(jí)別加上一個(gè)IX鎖

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

        • 當(dāng)想給記錄加S鎖時(shí),先給表加一個(gè)IS鎖,然后再給記錄加S鎖
        • 當(dāng)想給記錄加X(jué)鎖時(shí),先給表加IX鎖,然后再給記錄加X(jué)鎖

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

        • 如果想給表加S鎖,先看下表加沒(méi)加IX鎖,如果有的話,則表明此表中的記錄有X鎖,則需要等到IX鎖釋放掉后才可以加S鎖
        • 如果想給表加X(jué)鎖,先看下表加沒(méi)加IS鎖或者IX鎖,如果有的話,則表明此表中的記錄有S鎖或者X鎖,則需要等到IS鎖或者IX鎖釋放掉后才可以加X(jué)鎖

        這幾種鎖的兼容性如下表

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

        InnoDB中的行級(jí)鎖

        Record Lock(記錄鎖)

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

        Gap Lock(間隙鎖)

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

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

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

        Insert Intention Lock(插入意向鎖鎖)

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

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

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

        當(dāng)然不是!

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

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

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

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

        然后我們?cè)賮?lái)依此看下這個(gè)所結(jié)構(gòu)每個(gè)部分的信息都是什么意思

        • 鎖所在的事務(wù)信息:無(wú)論是表級(jí)鎖還是行級(jí)鎖,一個(gè)鎖屬于一個(gè)事務(wù),這里記載著該鎖對(duì)應(yīng)的信息
        • 索引信息:對(duì)于行級(jí)鎖來(lái)說(shuō),需要記錄一下加鎖的記錄屬于哪個(gè)索引
        • 表鎖/行鎖信息:行級(jí)鎖
          • Space_ID:記錄所在的表空間 *** Page Number**:記錄所在的頁(yè)號(hào)
          • n_bits:一條記錄對(duì)應(yīng)著一個(gè)比特;一個(gè)頁(yè)面包含多條記錄,用不同的比特來(lái)區(qū)分到底是那一條記錄加了鎖,有個(gè)計(jì)算公式如下(公式中是取商)n_bits = (1+(n_recs+LOCK_PAGE_BITMAP_MARGIN)/ 8)x 8LOCK_PAGE_BITMAP_MARGIN是固定的值為64,n_recs指當(dāng)前界面一共有多少條記錄(包含偽記錄以及在垃圾鏈表中的記錄),
        • type_mode:32比特的數(shù)
        • 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時(shí),表示表級(jí)鎖
          • LOCK_REC(十進(jìn)制的32):當(dāng)?shù)?比特位設(shè)置為1時(shí),表示行級(jí)鎖
        • rec_lock_type(行鎖的具體類型):其余的比特位表示

          • 第9比特設(shè)置為1時(shí),表示is_waiting為true,即當(dāng)前事務(wù)獲取鎖失敗,處于等待狀態(tài)
          • 第9比特設(shè)置為0時(shí),表示is_waiting為false,即當(dāng)前事務(wù)獲取鎖成功
          • LOCK_ORDINARY(十進(jìn)制的0):表示next-key鎖
          • LOCK_GAP(十進(jìn)制的512):當(dāng)?shù)?0比特位是1時(shí),表示gap鎖
          • LOCK_REC_NOT_GAP(十進(jìn)制的1024):也就是當(dāng)?shù)?1比特設(shè)置為1時(shí),表示Record Lock(記錄鎖)
          • LOCK_INSERT_INTENTION(十進(jìn)制的2048):也就是當(dāng)?shù)?2比特設(shè)置為1時(shí),表示Insert Intention Lock(插入意向鎖)
          • LOCK_WAIT(十進(jìn)制的256):也就是當(dāng)
        • 其他信息:此文章不討論

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

        舉個(gè)例子

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

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

        最后

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

        好文推薦


        瀏覽 51
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            2014天堂网 | 精品一区二区免费视频 | 欧美乱伦一级电影 | 欧美视频网站在线观看 | ass日本肉体艺术pics | 皇上和太监h高肉h | 国产精品一二三在线观看 | 美女又爽又黄视频毛茸茸 | 国产精品久久久久久久久懂色 | chinesefreehdxxxx高潮 |