RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文徹底搞懂MySQL鎖究竟鎖的啥2

jf_78858299 ? 來源:蟬沐風(fēng)的碼場 ? 作者:蟬沐風(fēng) ? 2023-03-03 10:13 ? 次閱讀

6. 意向鎖

6.1. 背景

前面提到的S鎖和X鎖的語法規(guī)則其實是針對記錄的,也就是行鎖,原因是InnoDB中行鎖用的最多。如果將鎖的粒度和鎖的基本模式排列組合一下,就會出現(xiàn)如下4種情況:

  • 行級S
  • 行級X
  • 表級S
  • 表級X

那么接下來的描述,也就順理成章了。

如果事務(wù)給一個表添加了表級S鎖,則:

  • 其他事務(wù)可以繼續(xù)獲得該表的S鎖,但是無法獲取該表的X鎖;
  • 其他事務(wù)可以繼續(xù)獲得該表某些行的S鎖,但是無法獲取該表某些行的X鎖。

如果事務(wù)給一個表添加了表級X鎖,則:

  • 不論是該表的S鎖、X鎖,還是該表某些行的S鎖、X鎖,其他事務(wù)都只能干瞪眼兒,啥也獲取不了。

挺好理解的吧,總之就是 S鎖只能和S鎖相容,X鎖和其他任何鎖都互斥 。問題來了,雖然用的不多,但是萬一我真的想給整個表添加一個S鎖或者X鎖怎么辦?

假如我要給表user添加一個S鎖,那就必須保證user在表級別上和行級別上都不能有X鎖,表級別上還好說一點,無非就是1個內(nèi)存結(jié)構(gòu)罷了,但是行X鎖呢?必須得逐行遍歷是否有行X鎖嗎?

同理,假如我要給表user添加一個X鎖,那就必須保證user在表級別上和行級別上都不能有任何鎖(SX都不能有),難不成得逐行遍歷是否有SX鎖嗎?

遍歷是不可能遍歷的!這輩子都不可能遍歷的!于是, 意向鎖 (Intension Lock)誕生了。

6.2. 概念

我們要避免遍歷,那最好的辦法就是在給行加鎖時,先在表級別上添加一個標(biāo)識。

  • 意向共享鎖(Intension Shared Lock):簡稱IS鎖,當(dāng)事務(wù)試圖給行添加S鎖時,需要先在表級別上添加一個IS鎖;
  • 意向排他鎖(Intension Exclusive Lock):簡稱IX鎖,當(dāng)事務(wù)試圖給行添加X鎖時,需要先在表級別上添加一個IX鎖。

這樣一來:

  • 如果想給user表添加一個S鎖(表級鎖),就先看一下user表有沒有IX鎖;如果有,就說明user表的某些行被加了X鎖(行鎖),需要等到行的X鎖釋放,隨即IX鎖被釋放,才可以在user表中添加S鎖;
  • 如果想給user表添加一個X鎖(表級鎖),就先看一下user有沒有IS鎖或IX鎖;如果有,就說明user表的某些行被加了S鎖或X鎖(行鎖),需要等到所有行鎖被釋放,隨即IS鎖或IX鎖被釋放,才可以在user表中添加X鎖。

需要注意的是,意向鎖和意向鎖之間是不沖突的,意向鎖和行鎖之間也不沖突。

只有在對表添加S鎖或X鎖時才需要判斷當(dāng)前表是否被添加了IS鎖或IX鎖,當(dāng)為表添加IS鎖或IX鎖時,不需要關(guān)心當(dāng)前表是否已經(jīng)被添加了其他IS鎖或IX鎖。

目前為止MySQL鎖的基本模式就介紹完了,接下來回到這片文章的題目,MySQL鎖,鎖住的到底是什么?由于InnoDB的行鎖用的最多,這里的鎖自然指的是行鎖。

7. 行鎖的原理

既然都叫行鎖了,我們姑且猜測一下,行鎖鎖住的是一行數(shù)據(jù)。我們做個實驗。

7.1. 沒有任何索引的表

我們先創(chuàng)建一張沒有任何索引的普通表,語句如下

CREATE TABLE `user_t1` (
  `id` int DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

表中數(shù)據(jù)如下:

mysql> SELECT * FROM user_t1;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | chanmufeng  |
|    2 | wanggangdan |
|    3 | wangshangju |
|    4 | zhaotiechui |
+------+-------------+

接下來我們在兩個session中開啟兩個事務(wù)。

  • 事務(wù)1,我們通過WHERE id = 1“鎖住”第1行數(shù)據(jù);
  • 事務(wù)2,我們通過WHERE id = 2"鎖住"第2行數(shù)據(jù)。

圖片

一件詭異的事情是,第2個加鎖的操作被阻塞了。實際上,T2中不管我們要給user_t1中哪行數(shù)據(jù)加鎖,都會失??!

為什么我SELECT一條數(shù)據(jù),卻給我鎖住了整個表?這個實驗直接推翻了我們的猜測, InnoDB的行鎖并非直接鎖定Record行 。

為什么沒有索引的情況下,給某條語句加鎖會鎖住整個表呢?別急,我們繼續(xù)。

7.2. 有主鍵索引的表

我們再創(chuàng)建一個表user_t2,語句如下:

CREATE TABLE `user_t2` (
	`id` int NOT NULL,
	`name` varchar(255) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

user_t1的不同之處在于為id創(chuàng)建了一個主鍵索引。表中數(shù)據(jù)依然如下:

mysql> SELECT * FROM user_t2;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | chanmufeng  |
|    2 | wanggangdan |
|    3 | wangshangju |
|    4 | zhaotiechui |
+------+-------------+

同樣開啟兩個事務(wù):

  • 事務(wù)1,通過WHERE id = 1“鎖住”第1行數(shù)據(jù);
  • 事務(wù)2
    • 依然使用WHERE id = 1嘗試加鎖,加鎖失敗;
    • 使用WHERE id = 2嘗試加鎖,加鎖成功。

圖片

既然鎖的不是Record行,難不成鎖的是id這一列嗎?

我們再做最后一個實驗。

7.3. 有唯一索引的表

我們再創(chuàng)建一個表user_t3,語句如下:

CREATE TABLE `user_t3` (
	`id` int NOT NULL,
	`name` varchar(255) DEFAULT NULL,
	PRIMARY KEY (`id`),
  UNIQUE KEY (`uk_name`) (`name`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

user_t2的不同之處在于為name列創(chuàng)建了一個唯一索引。表中數(shù)據(jù)依然如下:

mysql> SELECT * FROM user_t3;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | chanmufeng  |
|    2 | wanggangdan |
|    3 | wangshangju |
|    4 | zhaotiechui |
+------+-------------+

圖片

兩個事務(wù):

  • 事務(wù)1,通過name字段 “鎖住”name為“chanmufeng”的數(shù)據(jù);
  • 事務(wù)2
    • 依然使用WHERE name = “chanmufeng” 嘗試加鎖,可以預(yù)料,加鎖失?。?/li>
    • 使用WHERE id = 1嘗試給同樣的行加鎖,加鎖失敗。

通過3個實驗我們發(fā)現(xiàn),行鎖鎖住的既不是Record行,也不是Column列,那到底鎖住的是什么?我們對比一下,上文的3張表的不同點在于索引不同,其實 InnoDB的行鎖,就是通過鎖住索引來實現(xiàn)的 。

接下來回答3個問題。

8. 三個問題

8.1. 鎖住索引?沒有索引怎么辦?

你說鎖住索引?如果我不創(chuàng)建索引,MySQL鎖定個啥?

如果我們沒有設(shè)置主鍵,InnoDB會優(yōu)先選取一個不包含NULL值的Unique鍵作為主鍵,如果表中連Unique鍵也沒有的話,就會自動為每一條記錄添加一個叫做DB_ROW_ID的列作為默認(rèn)主鍵,只不過這個主鍵我們看不到罷了。

下圖是數(shù)據(jù)的行格式??床欢脑拸?qiáng)烈推薦看一下我上面給出的兩篇文章,說得非常明白。

圖片

行格式

8.2. 為什么第一個實驗會鎖表?

因為SELECT沒有用到索引,會進(jìn)行全表掃描,然后把DB_ROW_ID作為默認(rèn)主鍵的聚簇索引都給鎖住了。

8.3. 為什么通過唯一索引給數(shù)據(jù)加鎖,主鍵索引也會被鎖???

不管是Unique索引還是普通索引,它們的葉子結(jié)點中存儲的數(shù)據(jù)都不完整,其中只是存儲了作為索引并且排序好的列數(shù)據(jù)以及對應(yīng)的主鍵值。

因此我們通過索引查找數(shù)據(jù)數(shù)據(jù)實際上是在索引的B+樹中先找到對應(yīng)的主鍵,然后根據(jù)主鍵再去主鍵索引的B+樹的葉子結(jié)點中找到完整數(shù)據(jù),最后返回。所以雖然是兩個索引樹,但實際上是同一行數(shù)據(jù),必須全部鎖住。

下面給了一張圖,讓不了解索引的朋友大致了解一下。上半部分是name列創(chuàng)建的唯一索引的B+樹,下半部分是主鍵索引(也叫聚簇索引)。

假如我們通過WHERE name = '王鋼蛋'對數(shù)據(jù)進(jìn)行查詢,會先用到name列的唯一索引,最終定位到主鍵值為1,然后再到主鍵索引中查詢id = 1的數(shù)據(jù),最終拿到完整的行數(shù)據(jù)。

這兩張圖在我索引文章中都有哦~

圖片

MySQL鎖-索引

9. 總結(jié)

至此,我已經(jīng)回答了文章開頭的絕大多數(shù)問題。

MySQL鎖,是解決資源競爭問題的一種手段。有哪些競爭呢?讀—寫/寫—讀,寫—寫中都會出現(xiàn)資源競爭問題,不同的是前者可以通過MVCC的方式來解決,但是某些情況下你也不得不用鎖,因此我也順便解釋了鎖和MVCC的關(guān)系。

然后介紹了MySQL鎖的基本模式,包括共享鎖(S鎖)和排他鎖(X鎖),還引入了意向鎖。

最后解釋了鎖到底鎖的是什么的問題。通過3個實驗,最終解釋了InnoDB鎖本質(zhì)上鎖的是索引。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 計算機(jī)
    +關(guān)注

    關(guān)注

    19

    文章

    7488

    瀏覽量

    87849
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    804

    瀏覽量

    26528
  • MVCC
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    1465
收藏 人收藏

    評論

    相關(guān)推薦

    基于MySQL機(jī)制

    在數(shù)據(jù)庫系統(tǒng)中,為了保證數(shù)據(jù)的致性和并發(fā)控制,機(jī)制發(fā)揮著至關(guān)重要的作用。尤其在關(guān)系型數(shù)據(jù)庫MySQL中,其獨特的機(jī)制設(shè)計更是贏得了許多開發(fā)者的喜愛。 本文將詳細(xì)探討
    的頭像 發(fā)表于 09-30 11:16 ?874次閱讀

    redis分布式場景實現(xiàn)

    今天帶大家深入剖析下Redis分布式徹底搞懂它。 場景 既然要搞懂Redis分布式,那肯
    的頭像 發(fā)表于 09-25 17:09 ?714次閱讀

    請問DSPflash死后,RAM還可以用嗎,還是這塊芯片就徹底廢了?

    本帖最后由 只耳朵怪 于 2018-6-13 16:47 編輯 請問DSPflash死后,RAM還可以用嗎,還是這塊芯片就徹底廢了?
    發(fā)表于 06-13 04:19

    InnoDB的特點和狀態(tài)查詢

    MySQL探秘(五)InnoDB的類型和狀態(tài)查詢
    發(fā)表于 08-07 11:45

    讀懂eMMC究竟

    eMMC究竟?eMMC長什么樣?eMMC用在哪?主要是干嘛用的?eMMC究竟是如何工作的呢?
    發(fā)表于 06-18 06:04

    360為什么會入局智能市場

    很難界定智能究竟屬于哪個行業(yè)?智能是五金門鎖行業(yè)、安防行業(yè)、家居行業(yè)和產(chǎn)業(yè)互聯(lián)網(wǎng)行業(yè)的交匯產(chǎn)物。硬件是基礎(chǔ),安防及家居是應(yīng)用,網(wǎng)絡(luò)是消費渠道及用戶交互界面,物聯(lián)網(wǎng)讓智能
    發(fā)表于 11-05 15:21 ?1496次閱讀

    詳細(xì)介紹MySQL InnoDB存儲引擎各種不同類型的

    T1執(zhí)行時,需要獲取i=1的行的X(不需要獲取t1表的意向了);T2執(zhí)行時,需要獲取t1表的X,T2能否獲取到T1表的X
    的頭像 發(fā)表于 02-20 11:12 ?7639次閱讀
    詳細(xì)介紹<b class='flag-5'>MySQL</b> InnoDB存儲引擎各種不同類型的<b class='flag-5'>鎖</b>

    徹底搞懂PID到底是

    先來徹底搞懂PID到底是? PID,就是比例(proportional)、積分(integral)、微分(differential),是種很常見的控制算法。在工程實際中,應(yīng)用最為廣
    的頭像 發(fā)表于 11-13 18:21 ?2.5w次閱讀

    數(shù)據(jù)庫的機(jī)制真正的原理

    問候選人,你知道MySQL Innodb的,到底的是什么嗎?關(guān)于這個問題的回答,聽到過很多種,但是很少有人可以把他回答的很完美。因為想要回答好這個問題,需要對數(shù)據(jù)庫的隔離級別、索引等都有
    的頭像 發(fā)表于 11-12 09:33 ?2258次閱讀

    說說MySQL有哪些

    增加自增為 innodb_autoinc_lock_mode = 2 模式時,為什么主從環(huán)境會有不安全問題的說明
    的頭像 發(fā)表于 10-24 10:15 ?867次閱讀

    MySQL是怎么加行級的?有什么規(guī)則?

    是不是很多人都對 MySQL 加行級的規(guī)則搞的迷迷糊糊,對記錄會加的是 next-key 會加是間隙
    的頭像 發(fā)表于 11-17 09:28 ?803次閱讀

    徹底搞懂MySQL究竟1

    MySQL系列文章已經(jīng)鴿了挺久了,最近趕緊擠了擠時間,和大家聊MySQL。 只要學(xué)計算機(jī),「`
    的頭像 發(fā)表于 03-03 10:12 ?463次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>徹底</b><b class='flag-5'>搞懂</b><b class='flag-5'>MySQL</b><b class='flag-5'>鎖</b><b class='flag-5'>究竟</b><b class='flag-5'>鎖</b>的<b class='flag-5'>啥</b>1

    Linux互斥的作用 互斥是什么

    。如果釋放互斥時有個以上的線程阻塞,那么這些阻塞的線程會被喚醒,它們都會嘗試對互斥進(jìn)行加鎖,當(dāng)有個線程成功對互斥鎖上鎖之后,其它線程就不能再次上鎖了,只能再次陷入阻塞,等待下
    的頭像 發(fā)表于 07-21 11:13 ?931次閱讀

    自旋和互斥的區(qū)別有哪些

    自旋 自旋與互斥很相似,在訪問共享資源之前對自旋進(jìn)行上鎖,在訪問完成后釋放自旋(解鎖);事實上,從實現(xiàn)方式上來說,互斥
    的頭像 發(fā)表于 07-21 11:19 ?9485次閱讀

    互斥和自旋的實現(xiàn)原理

    互斥和自旋是操作系統(tǒng)中常用的同步機(jī)制,用于控制對共享資源的訪問,以避免多個線程或進(jìn)程同時訪問同資源,從而引發(fā)數(shù)據(jù)不致或競爭條件等問題。 互斥
    的頭像 發(fā)表于 07-10 10:07 ?484次閱讀
    RM新时代网站-首页