最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談MySQL next-key lock 加鎖范圍

 更新時間:2021年06月07日 09:54:30   作者:劉志航  
我們知道MYSQL NEXT-KEY LOCK是用來防止幻讀,那么MySQL next-key lock 加鎖范圍是多少,很多人都不知道,本文就來詳細的介紹一下

前言

某天,突然被問到 MySQL 的 next-key lock,我瞬間的反應就是:

這都是啥啥啥???

這一個截圖我啥也看不出來呀?

仔細一看,好像似曾相識,這不是《MySQL 45 講》里面的內(nèi)容么?

什么是 next-key lock

A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.

官網(wǎng)的解釋大概意思就是:next-key 鎖是索引記錄上的記錄鎖和索引記錄之前的間隙上的間隙鎖的組合。

先給自己來一串小問號???

  • 在主鍵、唯一索引、普通索引以及普通字段上加鎖,是鎖住了哪些索引?
  • 不同的查詢條件,分別鎖住了哪些范圍的數(shù)據(jù)?
  • for share 和 for update 等值查詢和范圍查詢的鎖范圍?
  • 當查詢的等值不存在時,鎖范圍是什么?
  • 當查詢條件分別是主鍵、唯一索引、普通索引時有什么區(qū)別?

既然啥都不懂,那只好從頭開始操作實踐一把了!

先看看看 《MySQL 45 講》中丁奇老師的結(jié)論:

看了這結(jié)論,應該可以解答一大部分問題,不過有一句非常非常重點的話需要關(guān)注:MySQL 后面的版本可能會改變加鎖策略,所以這個規(guī)則只限于截止到現(xiàn)在的最新版本,即 5.x 系列<=5.7.24,8.0 系列 <=8.0.13

所以,以上的規(guī)則,對現(xiàn)在的版本并不一定適用,下面我以 MySQL 8.0.25 版本為例,進行多角度驗證 next-key lock 加鎖范圍。

環(huán)境準備

MySQL 版本:8.0.25

隔離級別:可重復讀(RR)

存儲引擎:InnoDB

mysql> select @@global.transaction_isolation,@@transaction_isolation\G
mysql> show create table t\G

如何使用 Docker 安裝 MySQL,可以參考另一篇文章《使用 Docker 安裝并連接 MySQL》

主鍵索引

首先來驗證主鍵索引的 next-key lock 的范圍

此時數(shù)據(jù)庫的數(shù)據(jù)如圖所示,對主鍵索引來說此時數(shù)據(jù)間隙如下:

主鍵等值查詢 —— 數(shù)據(jù)存在

mysql> begin; select * from t where id = 10 for update;

這條 SQL,對 id = 10 進行加鎖,可以先思考一下加了什么鎖?鎖住了什么數(shù)據(jù)?

可以通過 data_locks 查看鎖信息,SQL 如下:

# mysql> select * from performance_schema.data_locks;
mysql> select * from performance_schema.data_locks\G

具體字段含義可以參考 官方文檔

結(jié)果主要包含引擎、庫、表等信息,咱們需要重點關(guān)注以下幾個字段:

  • INDEX_NAME:鎖定索引的名稱
  • LOCK_TYPE:鎖的類型,對于 InnoDB,允許的值為 RECORD 行級鎖 和 TABLE 表級鎖。
  • LOCK_MODE:鎖的類型:S, X, IS, IX, and gap locks
  • LOCK_DATA:鎖關(guān)聯(lián)的數(shù)據(jù),對于 InnoDB,當 LOCK_TYPE 是 RECORD(行鎖),則顯示值。當鎖在主鍵索引上時,則值是鎖定記錄的主鍵值。當鎖是在輔助索引上時,則顯示輔助索引的值,并附加上主鍵值。

結(jié)果很明顯,這里是對表添加了一個 IX 鎖 并對主鍵索引 id = 10 的記錄,添加了一個 X,REC_NOT_GAP 鎖,表示只鎖定了記錄。

同樣 for share 是對表添加了一個 IS 鎖并對主鍵索引 id = 10 的記錄,添加了一個 S 鎖。

可以得出結(jié)論:

對主鍵等值加鎖,且值存在時,會對表添加意向鎖,同時會對主鍵索引添加行鎖。

主鍵等值查詢 —— 數(shù)據(jù)不存在

mysql> select * from t where id = 11 for update;

如果是數(shù)據(jù)不存在的時候,會加什么鎖呢?鎖的范圍又是什么?

在驗證之前,分析一下數(shù)據(jù)的間隙。

  • id = 11 是肯定不存在的。但是加了 for update,這時需要加 next-key lock,id = 11 所屬區(qū)間為 (10,15] 的前開后閉區(qū)間;
  • 因為是等值查詢,不需要鎖 id = 15 那條記錄,next-key lock 會退化為間隙鎖;
  • 最終區(qū)間為 (10,15) 的前開后開區(qū)間。

使用 data_locks 分析一下鎖信息:

看下鎖的信息 X,GAP 表示加了間隙鎖,其中 LOCK_DATA = 15,表示鎖的是 主鍵索引 id = 15 之前的間隙。

此時在另一個 Session 執(zhí)行 SQL,答案顯而易見,是 id = 12 不可以插入,而 id = 15 是可以更新的。

可以得出結(jié)論,在數(shù)據(jù)不存在時,主鍵等值查詢,會鎖住該主鍵查詢條件所在的間隙。

主鍵范圍查詢(重點)

mysql> begin; select * from t where id >= 10 and id < 11 for update;

根據(jù) 《MySQL 45 講》分析得出下面結(jié)果:

  • id >= 10 定位到 10 所在的區(qū)間 (10,+∞);
  • 因為是 >= 存在等值判斷,所以需要包含 10 這個值,變?yōu)?[10,+∞) 前閉后閉區(qū)間;
  • id < 11 限定后續(xù)范圍,則根據(jù) 11 判斷下一個區(qū)間為 15 的前開后閉區(qū)間;
  • 結(jié)合起來則是 [10,15]。(不完全正確)

先看下 data_locks

可以看到除了表鎖之外,還有 id = 10 的行鎖(X,REC_NOT_GAP)以及主鍵索引 id = 15 之前的間隙鎖(X,GAP)。

所以實際上 id = 15 是可以進行更新的。也就是說前開后閉區(qū)間出現(xiàn)了問題,個人認為應該是 id < 11 這個條件判斷,導致不需要進行了鎖 15 這個行鎖。

結(jié)果驗證也是正確的,id = 12 插入阻塞,id = 15 更新成功。

當范圍的右側(cè)是包含等值查詢呢?

mysql> begin; select * from t where id > 10 and id <= 15 for update;

來分析一下這個 SQL:

id > 10 定位到 10 所在的區(qū)間 (10,+∞);id <= 15 定位是 (-∞, 15];結(jié)合起來則是 (10,15]。

同樣先看一下 data_locks

可以看出只添加了一個主鍵索引 id = 15 的 X 鎖。

驗證下 id = 15 是否可以更新?再驗證 id = 16 是否可以插入?

事實證明是沒有問題的!

當然,這里有小伙伴會說,在 《MySQL 45 講》 里面說這里有一個 bug,會鎖住下一個 next-key。

事實證明,這個 bug 已經(jīng)被修復了。修復版本為 MySQL 8.0.18。但是并沒有完全修復?。?!

參考鏈接地址:

https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-18.html

搜索關(guān)鍵字:Bug #29508068)

咱們可以分別用 8.0.17 進行復現(xiàn)一下:

在 8.0.17 中 id <= 15 會將 id = 20 這條數(shù)據(jù)也鎖著,而在 8.0.25 版本中則不會。所以這個 bug 是被修復了的。

再來看下是前開后閉還是前開后開的問題,嚴謹一下,使用 8.0.17 和 8.0.18 做比較。

現(xiàn)在我估計大概率是在 8.0.18 版本修復 Bug #29508068 的時候,把這個前開后閉給優(yōu)化成了前開后開了。

對比 data_locks 數(shù)據(jù):

注意紅色下劃線部分,在 8.0.17 版本中 id < 17 時 LOCK_MODE 是 X,而在 8.0.25 版本中則是 X,GAP

總結(jié)

本文主要通過實際操作,對主鍵加鎖時的 next-key lock 范圍進行了驗證,并查閱資料,對比版本得出不同的結(jié)論。

結(jié)論一:

  • 加鎖時,會先給表添加意向鎖,IX 或 IS;
  • 加鎖是如果是多個范圍,是分開加了多個鎖,每個范圍都有鎖;(這個可以實踐下 id < 20 的情況)
  • 主鍵等值查詢,數(shù)據(jù)存在時,會對該主鍵索引的值加行鎖 X,REC_NOT_GAP;
  • 主鍵等值查詢,數(shù)據(jù)不存在時,會對查詢條件主鍵值所在的間隙添加間隙鎖 X,GAP;
  • 主鍵等值查詢,范圍查詢時情況則比較復雜:
    • 8.0.17 版本是前開后閉,而 8.0.18 版本及以后,進行了優(yōu)化,主鍵時判斷不等,不會鎖住后閉的區(qū)間。
    • 臨界 <= 查詢時,8.0.17 會鎖住下一個 next-key 的前開后閉區(qū)間,而 8.0.18 及以后版本,修復了這個 bug。

優(yōu)化后,導致后開,這個不知道是因為優(yōu)化后,主鍵的區(qū)間會直接后開,還是因為是個 bug。具體小伙伴可以嘗試一下。

結(jié)論二

通過使用 select * from performance_schema.data_locks; 和操作實踐,可以看出 LOCK_MODE 和 LOCK_DATE 的關(guān)系:

LOCK_MODE LOCK_DATA 鎖范圍
X,REC_NOT_GAP 15 15 那條數(shù)據(jù)的行鎖
X,GAP 15 15 那條數(shù)據(jù)之前的間隙,不包含 15
X 15 15 那條數(shù)據(jù)的間隙,包含 15

LOCK_MODE = X 是前開后閉區(qū)間;X,GAP 是前開后開區(qū)間(間隙鎖);X,REC_NOT_GAP 行鎖。

基本已經(jīng)摸清主鍵的 next-key lock 范圍,注意版本使用的是 8.0.25。

疑問

  • 那唯一索引的 next-key lock 范圍是什么?
  • 當索引覆蓋時鎖的范圍和加鎖的索引分別是什么?
  • 我為什么說這個 bug 沒有完全修復,也是在非主鍵唯一索引中復現(xiàn)了這個 bug​。

文章篇幅有限,小伙伴可以先自己思考一下,盡量自己操作試一試,實踐出真知。至于具體答案,那就需要下一篇文章進行驗證并總結(jié)結(jié)論了。

到此這篇關(guān)于淺談MySQL next-key lock 加鎖范圍 的文章就介紹到這了,更多相關(guān)MySQL next-key lock 加鎖范圍 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • linux下備份MYSQL數(shù)據(jù)庫的方法

    linux下備份MYSQL數(shù)據(jù)庫的方法

    這是一個眾所周知的事實,對你運行中的網(wǎng)站的MySQL數(shù)據(jù)庫備份是極為重要的。
    2010-02-02
  • 深入解析MySQL中的longtext與longblob及應用場景

    深入解析MySQL中的longtext與longblob及應用場景

    MySQL作為廣泛應用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),提供了豐富的數(shù)據(jù)類型以滿足各種數(shù)據(jù)存儲需求,本文將深入探討MySQL中l(wèi)ongtext和longblob的特性、區(qū)別以及在實際項目中的應用場景,感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • window下mysql 8.0.15 安裝配置方法圖文教程

    window下mysql 8.0.15 安裝配置方法圖文教程

    這篇文章主要為大家詳細介紹了window下mysql 8.0.15 安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • MySQL需要根據(jù)特定順序排序的實現(xiàn)方法

    MySQL需要根據(jù)特定順序排序的實現(xiàn)方法

    在MySQL中,我們可以通過指定順序排序來在查詢結(jié)果中控制數(shù)據(jù)的排列順序,這種排序方式是非常有用的,本文就來介紹一下,感興趣的可以了解一下
    2023-11-11
  • 有關(guān)mysql中ROW_COUNT()的小例子

    有關(guān)mysql中ROW_COUNT()的小例子

    mysql中的ROW_COUNT()可以返回前一個SQL進行UPDATE,DELETE,INSERT操作所影響的行數(shù)
    2013-02-02
  • MySQL5.6與5.7版本區(qū)別有多大

    MySQL5.6與5.7版本區(qū)別有多大

    MySQL是一種關(guān)系型數(shù)據(jù)庫管理系統(tǒng),最常用的版本是5.6和5.7,mysql5.7是5.6的新版本,在沒有減少功能的情況下新增了功能與進行了優(yōu)化,例如新增了新的優(yōu)化器、原生JSON支持、多源復制,還優(yōu)化了整體的性能、GIS空間擴展、InnoDB...
    2024-03-03
  • MySQL連表查詢分組去重的實現(xiàn)示例

    MySQL連表查詢分組去重的實現(xiàn)示例

    本文將結(jié)合實例代碼,介紹MySQL連表查詢分組去重,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2021-07-07
  • Windows10下mysql 5.7.21 Installer版安裝圖文教程

    Windows10下mysql 5.7.21 Installer版安裝圖文教程

    這篇文章主要為大家詳細介紹了Windows10下mysql 5.7.21 Installer版安裝圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Mysql Workbench查詢mysql數(shù)據(jù)庫方法

    Mysql Workbench查詢mysql數(shù)據(jù)庫方法

    在本篇文章里小編給大家分享了個關(guān)于Mysql Workbench查詢mysql數(shù)據(jù)庫方法和步驟,有需要的朋友們學習下。
    2019-03-03
  • mysql共享鎖與排他鎖用法實例分析

    mysql共享鎖與排他鎖用法實例分析

    這篇文章主要介紹了mysql共享鎖與排他鎖用法,結(jié)合實例形式分析了mysql共享鎖與排他鎖相關(guān)概念、原理、用法及操作注意事項,需要的朋友可以參考下
    2019-09-09

最新評論

武城县| 那曲县| 阳泉市| 武胜县| 娄烦县| 通化市| 合肥市| 牡丹江市| 南川市| 西畴县| 平顶山市| 朝阳县| 鄯善县| 全南县| 江华| 延津县| 怀安县| 陕西省| 丹阳市| 澄城县| 乐业县| 绥中县| 柳林县| 白朗县| 伽师县| 兴海县| 宽城| 尼勒克县| 江西省| 渝北区| 临武县| 获嘉县| 舒城县| 托克逊县| 馆陶县| 怀仁县| 信丰县| 惠水县| 岐山县| 三河市| 页游|