欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

帶你一文理清MySQL的各種鎖

 更新時(shí)間:2024年06月25日 10:03:45   作者:戰(zhàn)斧  
MySQL?作為一種常用的關(guān)系型數(shù)據(jù)庫(kù),也提供了多種鎖類型,這篇文章主要給大家介紹了關(guān)于MySQL各種鎖的相關(guān)資料,文中通過(guò)代碼及圖文介紹的非常詳細(xì),需要的朋友可以參考下

一、MySQL的鎖指什么

我們先來(lái)看一下Mysql的基本構(gòu)成,如下圖,以前我們其實(shí)也介紹過(guò),MySQL數(shù)據(jù)庫(kù)總體分為三個(gè)部分:

  • Server層:負(fù)責(zé)處理客戶端連接、查詢解析和優(yōu)化、數(shù)據(jù)訪問(wèn)控制、事務(wù)處理、日志、replication和其他管理操作。
  • 存儲(chǔ)引擎:負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和檢索等操作。MySQL支持多個(gè)存儲(chǔ)引擎,如InnoDB、MyISAM、MEMORY等。
  • 物理磁盤(pán)層:真正存儲(chǔ)數(shù)據(jù)的位置,保存著數(shù)據(jù)庫(kù)數(shù)據(jù)以及各類日志。

我們?nèi)粘Uf(shuō)的MySQL的各種鎖,有的是由存儲(chǔ)引擎提供的,有些鎖是有Server層提供的),它們結(jié)合起來(lái)才形成了完整的鎖的體系

二、排他與共享

鎖從不同角度理解,其實(shí)會(huì)有不同的分類,也就是說(shuō)同一個(gè)東西,在不同的分類下叫不同的鎖,但其實(shí)它們并不沖突。在討論 MySQL 的鎖時(shí),一般我們會(huì)有這樣兩種分類:

  • 鎖的粒度
  • 是否排他

從鎖的粒度來(lái)看,可以分為全局鎖表鎖行鎖,顧名思義,鎖的層級(jí)分別是數(shù)據(jù)庫(kù)、某張表、以及表里的行。
從是否獨(dú)占來(lái)看,可以分為排它鎖、共享鎖

在innoDB,對(duì)于同一個(gè)資源,是允許設(shè)定 排它鎖(X) 和 共享鎖(S) 兩種的,它們的兼容關(guān)系如下:

XS
X沖突沖突
S沖突兼容

比如事務(wù)A對(duì)某一行上了共享鎖(S),此時(shí)再來(lái)一個(gè)事務(wù)B,如果B需要這個(gè)資源的共享鎖,那么它能立即獲得。如果B需要該資源的排它鎖,事務(wù)B就需要等待了。

而不同粒度的鎖,接下來(lái)我們以一一講解

三、全局鎖(Global Lock)

用于 限制整個(gè)數(shù)據(jù)庫(kù)實(shí)例 的訪問(wèn),當(dāng)執(zhí)行一些需要全局一致性的操作時(shí),例如備份、恢復(fù)等,可以使用全局鎖,如下命令

 FLUSH TABLES WITH READ LOCK

這個(gè)命令會(huì)對(duì)所有數(shù)據(jù)庫(kù)的所有表都上一個(gè)讀鎖,加完這個(gè)鎖后,所有的表都會(huì)被鎖定從而無(wú)法插入任何內(nèi)容了(mysql自己的系統(tǒng)日志表不在此列)

四、表鎖(Table Lock)

鎖定整個(gè)表,在執(zhí)行涉及整個(gè)表的操作時(shí),會(huì)對(duì)整個(gè)表進(jìn)行鎖定,避免其他事務(wù)對(duì)該表進(jìn)行并發(fā)操作。它的上鎖及解鎖語(yǔ)法如下

-- 加鎖
LOCK {TABLE | TABLES}
 tbl_name [[AS] alias] lock_type
 [, tbl_name [[AS] alias] lock_type] ...
lock_type: {
 READ [LOCAL]
 | WRITE
}

-- 釋放鎖
UNLOCK {TABLE | TABLES}

一般情況下,不建議使用這種表鎖,除非是對(duì)一組MyISAM的表來(lái)操作,那么提前將它們鎖定會(huì)提高效率

五、意向鎖(Intention Locks)

InnoDB 支持多粒度鎖,允許行鎖和表鎖共存。例如下面的語(yǔ)句就可以在指定的表上使用排他鎖(X鎖):

LOCK TABLES … WRITE

而為了同時(shí)避免遍歷行鎖的困境:比如事務(wù)A獲取了某一行的排它鎖,此時(shí)事務(wù)B想鎖表,就必須遍歷每一行檢查是否有鎖;同時(shí)也為了避免不同粒度間的鎖出現(xiàn)死鎖,所以InnoDB使用了意向鎖。意向鎖是表級(jí)別的鎖,它指示事務(wù)以后對(duì)表中的某一行需要哪種類型的鎖(共享的還是排他的)。有兩種類型的意向鎖:

  • 意向共享鎖(IS)表明事務(wù)打算對(duì)表中的單個(gè)行設(shè)置共享鎖
  • 意向排他鎖(IX)表示事務(wù)打算對(duì)表中的單個(gè)行設(shè)置排他鎖。

例如,SELECT…FOR SHARE 設(shè)置IS鎖,SELECT…FOR UPDATE 設(shè)置一個(gè)IX鎖。
在事務(wù)獲得表中某一行的共享鎖之前,它必須首先獲得表上的IS鎖或更強(qiáng)的鎖。
在事務(wù)獲得表中某一行的排他鎖之前,它必須首先獲得該表上的IX鎖

表級(jí)鎖類型兼容性如下表所示:

XIXSIS
X沖突沖突沖突沖突
IX沖突兼容沖突兼容
S沖突沖突兼容兼容
IS沖突兼容兼容兼容

這個(gè)表的理解其實(shí)很簡(jiǎn)單:

(1)X 作為表的排他鎖,和其他所有表鎖沖突

(2)IX 代表準(zhǔn)備修改某一行,此時(shí)如果有人持有表,不論是 X 還是 S,為了防止沖突或不一致,所以會(huì)返回沖突

如果鎖與現(xiàn)有鎖兼容,則將鎖授予請(qǐng)求事務(wù),但如果它與現(xiàn)有鎖沖突,則不會(huì)授予。事務(wù)等待,直到?jīng)_突的現(xiàn)有鎖被釋放。如果鎖請(qǐng)求與現(xiàn)有鎖沖突,并且由于會(huì)導(dǎo)致死鎖而無(wú)法授予,則會(huì)發(fā)生錯(cuò)誤。

意向鎖的主要目的是顯示某人正在鎖定表中的一行,或者將要鎖定表中的一行,作為行鎖前置的隱式鎖。也就是說(shuō)若你僅使用表鎖,或僅使用行鎖,意向鎖是不會(huì)讓你阻塞的。只有你在持有行鎖的情況下又使用表鎖,它才能發(fā)揮它的用處

六、行級(jí)鎖(Row Lock)

在InnoDB存儲(chǔ)引擎中,默認(rèn)使用的是行級(jí)鎖。它可以實(shí)現(xiàn)更細(xì)粒度的并發(fā)控制,只鎖定部分行,而不是整個(gè)表,提高了并發(fā)性能。而從實(shí)際表現(xiàn)來(lái)說(shuō),其又分為三種 記錄鎖(Record Locks)、間隙鎖(Gap Locks),以及所謂臨鍵鎖(Next-Key Locks)。實(shí)際上在源碼中,這三種鎖其實(shí)叫 LOCK_REC_NOT_GAP、LOCK_GAPLOCK_ORDINARY

/* Precise modes /
/* this flag denotes an ordinary next-key lock in contrast to LOCK_GAP or
LOCK_REC_NOT_GAP /
constexpr uint32_t LOCK_ORDINARY = 0;/* when this bit is set, it means that the lock holds only on the gap before
the record; for instance, an x-lock on the gap does not give permission to
modify the record on which the bit is set; locks of this type are created
when records are removed from the index chain of records /
constexpr uint32_t LOCK_GAP = 512;/* this bit means that the lock is only on the index record and does NOT
block inserts to the gap before the index record; this is used in the case
when we retrieve a record with a unique key, and is also used in locking
plain SELECTs (not part of UPDATE or DELETE) when the user has set the READ
COMMITTED isolation level */
constexpr uint32_t LOCK_REC_NOT_GAP = 1024;

1. 記錄鎖(Record Locks)

記錄鎖是索引記錄上的鎖,例如,

SELECT c1 FROM t WHERE c1=10 For update;

這樣就能阻止任何其他事務(wù)插入、更新或刪除c1是10為的行。
記錄鎖總是鎖定索引,即使定義的表沒(méi)有索引也是如此。對(duì)于這樣的情況,InnoDB創(chuàng)建一個(gè)隱藏的聚集索引,并使用該索引進(jìn)行記錄鎖定

2. 間隙鎖(Gap Locks)

如果我們把隔離級(jí)別設(shè)定為可重復(fù)讀(RR),MySQL就會(huì)為我們解決”幻讀“現(xiàn)象,這里面除了MVCC的作用外,還會(huì)在此時(shí)引入”間隙鎖“的概念,間隙鎖本質(zhì)上是 在索引記錄之間的間隙上的鎖,或者在第一個(gè)索引記錄之前或最后一個(gè)索引記錄之后的間隙上的鎖。比如說(shuō)當(dāng)我們執(zhí)行這樣一個(gè)SQL時(shí)

SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 For Update

就會(huì)防止其他事務(wù)將值15插入到列t.c1中,因?yàn)榉秶兴鞋F(xiàn)有值之間的間隙被鎖定。

3. 臨鍵鎖(Next-Key Locks)

next-key鎖是索引記錄上的記錄鎖和索引記錄之前的間隙上的間隙鎖的組合。InnoDB執(zhí)行行級(jí)鎖的方式是,當(dāng)它搜索或掃描一個(gè)表索引時(shí),它會(huì)在遇到的索引記錄上設(shè)置共享鎖或排他鎖。因此,行級(jí)鎖實(shí)際上是索引記錄鎖。索引記錄上的next-key鎖也會(huì)影響該索引記錄之前的“間隙”。也就是說(shuō),next-key鎖是索引記錄鎖加上索引記錄前面的間隙鎖。

假設(shè)索引包含值10、11、13和20。此索引的Next-Key Locks鎖定則覆蓋以下區(qū)間,其中圓括號(hào)表示不包含區(qū)間端點(diǎn),方括號(hào)表示包含端點(diǎn):

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

對(duì)于最后一個(gè)間隔,next-key鎖鎖定索引中最大值以上的間隙,以及值高于索引中任何實(shí)際值的“supremum”偽記錄。”supremum“不是一個(gè)真正的索引記錄,因此,實(shí)際上,這個(gè)next-key鎖只鎖定最大索引值后面的間隙。默認(rèn)情況下,InnoDB運(yùn)行在REPEATABLE READ事務(wù)隔離級(jí)別。在這種情況下,InnoDB使用next-key鎖進(jìn)行搜索和索引掃描,這可以防止幻行。

4. 插入意向鎖(Insert Intention Locks)

學(xué)習(xí)了上面的間隙鎖,我們不難知曉,想要插入新數(shù)據(jù)通常需要先獲得間隙鎖(隔離級(jí)別為可重復(fù)讀及以上)。按照常理來(lái)說(shuō),如果有多個(gè)事務(wù)都想往一個(gè)間隙里插入數(shù)據(jù),它們只要慢慢排隊(duì)就好了,但是,我們還需要意識(shí)到,一旦事務(wù)A插入一條數(shù)據(jù)成功,原先的間隙可能就會(huì)變成兩個(gè)間隙,事務(wù)B可能又被A新誕生的這個(gè)間隙所阻礙。為了優(yōu)化這種插入排隊(duì)的情況,innodb提出了插入意向鎖的概念:

An insert intention lock is a type of gap lock set by INSERT operations prior to row insertion. This lock
signals the intent to insert in such a way that multiple transactions inserting into the same index gap
need not wait for each other if they are not inserting at the same position within the gap

插入意圖鎖是insert操作在行插入之前設(shè)置的一種間隙鎖。這個(gè)鎖以這樣一種方式表示插入的意圖,即插入到相同索引間隙中的多個(gè)事務(wù)如果不在間隙內(nèi)的相同位置插入,則不需要彼此等待

也就是說(shuō),插入操作在獲取間隙鎖之前,會(huì)先獲取到插入意向鎖,下面的示例演示了一個(gè)事務(wù)在獲得插入記錄的排他鎖之前使用插入意圖鎖。該示例涉及兩個(gè)客戶機(jī)A和b??蛻魴C(jī)A創(chuàng)建一個(gè)包含兩個(gè)索引記錄(90和102)的表,然后啟動(dòng)一個(gè)事務(wù),對(duì)ID大于100的索引記錄設(shè)置排他鎖。排他鎖包括記錄102之前的間隙鎖:

mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
mysql> INSERT INTO child (id) values (90),(102);

mysql> START TRANSACTION;
mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;
+-----+
| id |
+-----+
| 102 |
+-----+

客戶端B開(kāi)始一個(gè)事務(wù),向缺口間隙插入一條記錄,事務(wù)在等待獲得排他鎖時(shí)接受插入意圖鎖:

mysql> START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);

在SHOW ENGINE INNODB STATUS和INNODB monitor輸出中,插入意圖鎖的事務(wù)數(shù)據(jù)如下所示:

RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000066; asc f;;
 1: len 6; hex 000000002215; asc " ;;
 2: len 7; hex 9000000172011c; asc r ;;...

5. 行鎖總結(jié)

其實(shí)對(duì)于行鎖,現(xiàn)在解析的文章有很多,我們后續(xù)也可能結(jié)合源碼進(jìn)行更深入的解釋。但在這里我們可以先進(jìn)行總結(jié)(源于Mysql源碼版本8.0.30)

  • 鎖基于掃描到的索引,對(duì)于innoDB,哪怕你沒(méi)有顯示建立索引,每一張表也都至少會(huì)有一個(gè)索引(即其聚集索引
  • 間隙鎖(Gap Locks) 只有在隔離級(jí)別為可重復(fù)讀以上才會(huì)有
  • 隔離級(jí)別為讀未提交/讀提交時(shí),行級(jí)鎖默認(rèn)使用記錄鎖(Record Locks),隔離級(jí)別為可重復(fù)讀/序列化時(shí),行級(jí)鎖默認(rèn)使用的是臨鍵鎖(Next-Key Locks)
  • 間隙鎖(Gap Locks) 的目的是不讓這段間隙內(nèi)插入新的數(shù)據(jù),因此其設(shè)計(jì)與傳統(tǒng)意義上的共享/排他概念不一樣。比如:事務(wù)A在一個(gè)間隙上持有共享間隙鎖(間隙s鎖),而事務(wù)B可以在同一個(gè)間隙上持有排他性間隙鎖(間隙x鎖)

七、自增鎖(AUTO-INC Locks)

AUTO-INC鎖是一種特殊的表級(jí)鎖,用于在具有AUTO_INCREMENT列的表中插入事務(wù)。

在最簡(jiǎn)單的情況下,如果一個(gè)事務(wù)正在向表中插入值,那么任何其他事務(wù)都必須等待對(duì)該表進(jìn)行自己的插入,以便第一個(gè)事務(wù)插入的行接收連續(xù)的主鍵值。innodb_autoinc_lock_mode變量控制用于自動(dòng)增量鎖定的算法。它允許您選擇如何在可預(yù)測(cè)的自動(dòng)遞增值序列和插入操作的最大并發(fā)性之間進(jìn)行權(quán)衡。

這里有 0、1、2 三種模式可選

  • 0(traditional):這是最常用的模式。在這種模式下,InnoDB使用一個(gè)全局的互斥鎖(AUTO-INC鎖)來(lái)保護(hù)自增主鍵的訪問(wèn)。當(dāng)有一個(gè)事務(wù)插入新記錄時(shí),其他事務(wù)必須等待該事務(wù)釋放AUTO-INC鎖后才能插入新記錄,該鎖通常保持到語(yǔ)句結(jié)束(而不是事務(wù)結(jié)束)。

  • 1(consecutive):在這種模式下,InnoDB使用一個(gè)遞增的互斥鎖(AUTO-INC鎖)來(lái)保護(hù)自增主鍵的訪問(wèn)。如果我們可以預(yù)知插入的數(shù)據(jù)條數(shù),InnoDB會(huì)為每個(gè)事務(wù)分配一個(gè)獨(dú)立的自增值區(qū)間。當(dāng)一個(gè)事務(wù)需要插入自增值時(shí),它就可以在自己的區(qū)間內(nèi)找到一個(gè)可用的自增值,然后將其插入到表中。通過(guò)為每個(gè)事務(wù)分配獨(dú)立的自增值區(qū)間,Consecutive模式可以實(shí)現(xiàn)并行插入,這種模式適用于具有高并發(fā)讀寫(xiě)的應(yīng)用,可以提高性能。

  • 2(interleaved):這種模式是在MySQL 8.0中引入的新模式。在這種模式下,事務(wù)們都不再持有表級(jí)AUTO-INC鎖,該模式可以支持多個(gè)語(yǔ)句可以同時(shí)生成數(shù)字,也就是說(shuō),數(shù)字的分配在多個(gè)語(yǔ)句之間交錯(cuò)進(jìn)行。

需要注意的是,在我們使用它不同種類的插入語(yǔ)句的時(shí)候,consecutive 自增鎖有可能還是會(huì)使用全局互斥鎖的樣子,因?yàn)椴皇敲恳环N insert 都能提前預(yù)知其數(shù)量的,比如下面這樣的插入:

INSERT INTO t1 (c2) SELECT ... from another table ...

總結(jié) 

到此這篇關(guān)于MySQL各種鎖的文章就介紹到這了,更多相關(guān)MySQL各種鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL如何判斷字符串為NULL或者為空字符串

    MySQL如何判斷字符串為NULL或者為空字符串

    這篇文章主要介紹了MySQL如何判斷字符串為NULL或者為空字符串,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • MYSQL8 通過(guò)ibd文件恢復(fù)表數(shù)據(jù)的方法

    MYSQL8 通過(guò)ibd文件恢復(fù)表數(shù)據(jù)的方法

    這篇文章主要介紹了MYSQL8 通過(guò)ibd文件恢復(fù)表數(shù)據(jù)的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • mysql存儲(chǔ)過(guò)程與函數(shù)學(xué)習(xí)與實(shí)踐方式

    mysql存儲(chǔ)過(guò)程與函數(shù)學(xué)習(xí)與實(shí)踐方式

    下面小編就為大家分享一篇mysql存儲(chǔ)過(guò)程與函數(shù)學(xué)習(xí)與實(shí)踐方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • 淺談MySQL中g(shù)roup_concat()函數(shù)的排序方法

    淺談MySQL中g(shù)roup_concat()函數(shù)的排序方法

    下面小編就為大家?guī)?lái)一篇淺談MySQL中g(shù)roup_concat()函數(shù)的排序方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12
  • SQL基礎(chǔ)的查詢語(yǔ)句

    SQL基礎(chǔ)的查詢語(yǔ)句

    這篇文章主要給大家分享的是SQL基礎(chǔ)的查詢語(yǔ)句,SQL語(yǔ)句中,查詢是使用最多的操作,SQL不僅能夠查詢表中的數(shù)據(jù),還可以返回算術(shù)運(yùn)算、表達(dá)式的結(jié)果等,接下來(lái)就一起了解一下基本的查詢語(yǔ)句,需要的朋友可以參考一下
    2021-11-11
  • 如何用SQL命令查看Mysql數(shù)據(jù)庫(kù)大小

    如何用SQL命令查看Mysql數(shù)據(jù)庫(kù)大小

    本篇文章是對(duì)用SQL命令查看Mysql數(shù)據(jù)庫(kù)大小的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • MySQL5.7中 performance和sys schema中的監(jiān)控參數(shù)解釋(推薦)

    MySQL5.7中 performance和sys schema中的監(jiān)控參數(shù)解釋(推薦)

    在MySQL5.7中,performance schema有很大改進(jìn),包括引入大量新加入的監(jiān)控項(xiàng)、降低占用空間和負(fù)載,以及通過(guò)新的sys schema機(jī)制顯著提升易用性。下面通過(guò)本文給大家介紹 MySQL5.7中 performance和sys schema中的監(jiān)控參數(shù)解釋,需要的朋友可以參考下
    2017-08-08
  • mysql查詢的時(shí)候給字段賦默認(rèn)值操作

    mysql查詢的時(shí)候給字段賦默認(rèn)值操作

    這篇文章主要介紹了mysql查詢的時(shí)候給字段賦默認(rèn)值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • MySQL如何使用時(shí)間作為判斷條件

    MySQL如何使用時(shí)間作為判斷條件

    這篇文章主要介紹了MySQL如何使用時(shí)間作為判斷條件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • MySQL筆記 —SQL運(yùn)算符

    MySQL筆記 —SQL運(yùn)算符

    這篇文章主要介紹了SQL運(yùn)算符,在sql語(yǔ)言中常用的運(yùn)算符有這幾種:算術(shù)運(yùn)算符、賦值運(yùn)算符、比較運(yùn)算符、邏輯運(yùn)算符,下面面基于記住運(yùn)算符資料展開(kāi)文章內(nèi)容,需要的小伙伴可以參考一下
    2022-01-01

最新評(píng)論