自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

什么是MySQL鎖?有哪些鎖類型?

開發(fā) 前端
很多人都一樣,在剛開始學(xué)習(xí)MySQL中鎖的時(shí)候,網(wǎng)上一查出來(lái)一堆,什么表鎖、行鎖、讀鎖、寫鎖、悲觀鎖、樂觀鎖等等等,直接整個(gè)人就懵了。

為什么需要引入鎖

鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或線程并發(fā)訪問某一資源的一種機(jī)制,在并發(fā)事務(wù)下保證數(shù)據(jù)的正確和唯一性。

圖片圖片

鎖在 MySQL 中是非常重要的一部分,對(duì) MySQL 的數(shù)據(jù)訪問并發(fā)有著舉足輕重的影響

MySQL中的鎖是在服務(wù)器層或存儲(chǔ)引擎層實(shí)現(xiàn)的,不同的存儲(chǔ)引擎的鎖機(jī)制也有較大的區(qū)別。

MySQL鎖的實(shí)現(xiàn)

很多人都一樣,在剛開始學(xué)習(xí)MySQL中鎖的時(shí)候,網(wǎng)上一查出來(lái)一堆,什么表鎖、行鎖、讀鎖、寫鎖、悲觀鎖、樂觀鎖等等等,直接整個(gè)人就懵了。

本文我們將以鎖粒度的角度去看MySQL鎖的分類情況

沒事,先看看小許歸納的鎖知識(shí)大綱,先對(duì)鎖的位置和鎖歸屬的存儲(chǔ)引擎有個(gè)前置了解!

圖片圖片

全局鎖

全局鎖就是對(duì)整個(gè)數(shù)據(jù)庫(kù)實(shí)例加鎖,MySQL有個(gè)全局讀鎖的命令如下:

flush tables with read lock(FTWRL)

執(zhí)行后,整個(gè)數(shù)據(jù)庫(kù)就處于只讀狀態(tài)(不能寫入) 了,這個(gè)時(shí)候其他線程執(zhí)行數(shù)據(jù)更新語(yǔ)句(數(shù)據(jù)的增刪改),數(shù)據(jù)定義語(yǔ)句(建表、修改表結(jié)構(gòu)等)等,都會(huì)被阻塞。

解鎖命令:

unlock tables

使用場(chǎng)景舉例:

主要應(yīng)用于做全庫(kù)邏輯備份,原理也很簡(jiǎn)單在全局鎖期間數(shù)據(jù)或表結(jié)構(gòu)不會(huì)被更新,備份后文件的數(shù)據(jù)與預(yù)期也就一樣了。

當(dāng)時(shí)加上全局鎖,意味著整個(gè)數(shù)據(jù)庫(kù)都是只讀狀態(tài),如果備份時(shí)間過長(zhǎng)就導(dǎo)致其他

Mysql中數(shù)據(jù)備份使用的命令是mysqldump命令

當(dāng)使用參數(shù)-single-transaction的時(shí)候,導(dǎo)出數(shù)據(jù)之前就會(huì)啟動(dòng)一個(gè)事務(wù),來(lái)確保拿到一致性視圖,而由于MVCC的支持,這個(gè)過程中數(shù)據(jù)是可以正常更新的,因?yàn)樽x取的數(shù)據(jù)在更新前已確認(rèn)。

頁(yè)鎖

頁(yè)級(jí)鎖是 MySQL 中比較獨(dú)特的一種鎖定級(jí)別,主要應(yīng)用于 BDB 存儲(chǔ)引擎,我們實(shí)際中基本上用的是InnoDB引擎,這里對(duì)頁(yè)鎖就不多展開了。

表鎖

MyISAM和InnoDB都支持表級(jí)鎖,但是InnoDB默認(rèn)的是行級(jí)鎖。

表鎖下面又分了以下四種

圖片圖片

表鎖

顧名思義,就是直接對(duì)表進(jìn)行加鎖,可以使用下面命令:

//加讀鎖
lock tables table_name read;
//加寫鎖
lock tables table_name write;
// 釋放當(dāng)前會(huì)話的所有表鎖
unlock tables

如果加的是寫鎖,當(dāng)對(duì)表進(jìn)行寫操作時(shí)也會(huì)被阻塞,直到寫鎖被釋放。

不過盡量避免在使用 InnoDB 引擎的表使用表鎖,因?yàn)楸礞i的顆粒度太大,會(huì)影響并發(fā)性能。

元數(shù)據(jù)鎖

MySQL5.5引入了元數(shù)據(jù)鎖(meta data lock - MDL),它不需要顯式使用,在訪問一個(gè)表的時(shí)候會(huì)被自動(dòng)加上。

  • ? 對(duì)表數(shù)據(jù)進(jìn)行 CRUD 操作時(shí),加 MDL 讀鎖
  • ? 對(duì)表結(jié)構(gòu)變更操作的時(shí)候,加 MDL 寫鎖

既然是自動(dòng)加鎖,那釋放也是自動(dòng)的!

事務(wù)執(zhí)行期間,MDL 是一直持有的, 在事務(wù)提交后MDL才會(huì)釋放。

意向鎖(Intention Lock)

意向鎖主要是在對(duì)數(shù)據(jù)表的行記錄加共享鎖(S鎖)、獨(dú)占鎖(X鎖)之前,需要先在表級(jí)別加上一個(gè)意向鎖。

在InnoDB引擎中,當(dāng)執(zhí)行查詢操作,需要先對(duì)表加上「意向共享鎖」,然后對(duì)該記錄加【共享鎖】

意向鎖有兩種類型:

意向共享鎖(IS鎖):一個(gè)事務(wù)給一個(gè)數(shù)據(jù)行加共享鎖時(shí),必須先獲得表的意向共享鎖

意向獨(dú)占鎖(IX鎖): 一個(gè)事務(wù)給一個(gè)數(shù)據(jù)行加獨(dú)占鎖時(shí),必須先獲得表的意向獨(dú)占鎖

為什么需要先加意向鎖?

意向鎖的目的是更加快速的判斷數(shù)據(jù)表表里是否有記錄被加鎖。

比如我們要加【獨(dú)占表鎖】,先在表級(jí)別加了【意向獨(dú)占鎖】,那么在加【獨(dú)占鎖】時(shí),直接查該表是否有意向獨(dú)占鎖,如果有就表示表記錄存在獨(dú)占鎖,這樣就不用去遍歷表記錄去查看行記錄是否存在獨(dú)占鎖了。

加鎖命令如下:

//加上意向共享鎖,然后對(duì)讀取的記錄加共享鎖
select ... lock in share mode;

//先表上加上意向獨(dú)占鎖,然后對(duì)讀取的記錄加獨(dú)占鎖
select ... for update;

AUTO-INC鎖

字面意思是用來(lái)控制自動(dòng)自增的鎖?

是的,一般來(lái)說(shuō)我們會(huì)在表中設(shè)置一個(gè)字段聲明 AUTO_INCREMENT 的自增ID字段。

AUTO-INC鎖在自增字段起了個(gè)什么作用呢?

當(dāng)使用INSERT語(yǔ)句插入一條新記錄時(shí),MySQL會(huì)自動(dòng)為自增字段加鎖,防止其他并發(fā)的插入操作同時(shí)獲取相同的自增值。

其他事務(wù)要等待,直到執(zhí)行完插入語(yǔ)句之后才會(huì)釋放鎖。

這就保證了數(shù)據(jù)表的 AUTO_INCREMENT 字段的值是連續(xù)遞增。

好吧,原來(lái)這個(gè)AUTO_INC鎖的作用是這樣的,以前我還一直不知道呢!

?? AUTO-INC鎖有什么問題?

大批量數(shù)據(jù)在一條語(yǔ)句中插入時(shí)(INSERT SELECT ),會(huì)帶來(lái)一些性能上的影響,從而阻塞其他事務(wù)的插入操作!

?? MySQL是如何進(jìn)行AUTO-INC鎖性能優(yōu)化的?

MYSQL 5.1.22版本開始,InnoDB存儲(chǔ)引擎使用一種輕量級(jí)互斥鎖(Mutex)來(lái)控制自增列增長(zhǎng)

通過參數(shù)innodb_autoinc_lock_mode來(lái)控制 可以設(shè)定3個(gè)值分別是0,1,2

  • ? 0:traditional 每次insert都采用 AUTO-INC 鎖,語(yǔ)句執(zhí)行結(jié)束后才釋放鎖,但并發(fā)能力較弱
  • ? 1:consecutive 對(duì)于SIMPLE INSERT,使用輕量級(jí)互斥鎖,對(duì)于BULK INSERT,使用AUTO-inc locking
  • ? 2:interleaved 采用輕量級(jí)鎖,申請(qǐng)自增主鍵后就釋放鎖,但可能會(huì)造成insert分配的id順序不一致

?? 一個(gè)事務(wù)中存在多個(gè)insert語(yǔ)句,auto-inc鎖是如何申請(qǐng)的?

自增鎖跟事務(wù)無(wú)關(guān),即使多個(gè)insert語(yǔ)句在同一個(gè)十五中,每個(gè)insert還是都會(huì)申請(qǐng)罪行的自增鎖。

圖片圖片

行鎖

顧名思義,行鎖就是給數(shù)據(jù)庫(kù)表中每行數(shù)據(jù)加鎖,行鎖是加在索引上的

比如某個(gè)表中id字段是主鍵,如果給id=2這條記錄加鎖,那這把鎖是加在主鍵索引(聚簇索引)上的

行鎖使用分類

我們講表鎖的時(shí)候說(shuō)到了意向鎖,在對(duì)數(shù)據(jù)表的行記錄加共享鎖(S鎖)、獨(dú)占鎖(X鎖)之前,需要先在表級(jí)別加上一個(gè)意向鎖 。

InnoDB 行級(jí)鎖按照使用方式分為:共享鎖(S鎖)、排它鎖(X鎖)

圖片圖片

讀鎖會(huì)阻塞寫(X),但是不會(huì)堵塞讀(S),而寫鎖則會(huì)把讀(S)和寫(X)都堵塞

對(duì)于普通 select 語(yǔ)句,innodb 不會(huì)加任何鎖。如果想在select操作的時(shí)候加上 S鎖 或者 X鎖,需要我們手動(dòng)加鎖。

//查詢記錄加共享鎖
select ... lock in share mode;

//查詢記錄加獨(dú)占鎖
select ... for update;

InnoDB 在RR(MySQL默認(rèn)隔離級(jí)別) ,對(duì)于 update、delete 和 insert 語(yǔ)句, 會(huì)自動(dòng)給涉及的數(shù)據(jù)集加排它鎖(X)

InnoDB支持3種行鎖的算法,分別是:

  • ? Record Lock: 單個(gè)行記錄上的鎖

? Gap Lock: 間隙鎖,鎖定一個(gè)范圍,但不包含記錄本身

? Next-Key Lock: Gap Lock與Record Lock的結(jié)合,鎖定一個(gè)范圍,并且鎖定記錄本身

我們?cè)诜治鲂墟i三種算法是要結(jié)合存在共享鎖(S)和排他鎖(X)場(chǎng)景,我們接著看這三種

記錄鎖 Record Lock

Record Lock 稱為記錄鎖,鎖住的是一條記錄

SELECT * FROM `demo` WHERE `id`= 23 FOR UPDATE;

上面SQL在 id = 23 的記錄上加上記錄鎖(X鎖),這樣其他事務(wù)就無(wú)法插入,更新,刪除 id=23 這一行。

下面SQL是對(duì)主鍵索引 與 唯一索引 對(duì)數(shù)據(jù)行進(jìn)行 UPDATE 操作時(shí),也會(huì)對(duì)該行數(shù)據(jù)加記錄鎖:

UPDATE demo SET name = 'xiaoxu' WHERE id = 23;

記錄鎖是鎖住記錄,鎖住索引記錄,而不是真正的數(shù)據(jù)記錄。

?? 表中沒有建索引怎么辦?

即使該表上沒有任何索引,那么innodb會(huì)在后臺(tái)創(chuàng)建一個(gè)隱藏的聚集主鍵索引,那么鎖住的就是這個(gè)隱藏的聚集主鍵索引。

間隙鎖 GAP Lock

間隙鎖 是 InnoDB 在 RR(可重復(fù)讀) 隔離級(jí)別 下為了解決幻讀問題時(shí)引入的鎖機(jī)制。

Tips:使用間隙鎖GAP Lock鎖住的是一個(gè)區(qū)間,而不僅僅是這個(gè)區(qū)間中的每一條數(shù)據(jù)

SELECT * FROM demo WHERE id > 23 and id < 25 FOR UPDATE

上面語(yǔ)句對(duì)id范圍(23, 25)的數(shù)據(jù)行加間隙鎖鎖,此時(shí)就無(wú)法插入id= 24的數(shù)據(jù)

臨鍵鎖 Next-Key Lock

Next-key Lock 臨鍵鎖是記錄鎖和間隙鎖的組合,鎖的范圍是左開右閉區(qū)間的數(shù)據(jù)(即在某條記錄以及這條記錄前面間隙上的鎖)。

InnoDB是使用Next-Key Lock來(lái)解決幻讀問題的,在數(shù)據(jù)行上的非唯一索引列上都會(huì)存在一把臨鍵鎖。

注意:臨鍵鎖只與 非唯一索引列 有關(guān),在 唯一索引列(包括主鍵列)上不存在臨鍵鎖。

圖片圖片

上面表結(jié)構(gòu)中age字段為普通索引

-- 事務(wù)A 更新age=24的記錄 
UPDATE demo SET name = Vladimir WHERE age = 24;
-- 事務(wù)B 執(zhí)行插入
INSERT INTO demo VALUES(100, 26, 'xiaoxu');

事務(wù) A 在對(duì) age 為 24 的列進(jìn)行 UPDATE 操作的同時(shí),也獲取了 (24, 26] 這個(gè)區(qū)間內(nèi)的臨鍵鎖,所以此時(shí)事務(wù)B會(huì)被阻塞。

問題

臨鍵鎖 Next-Key Lock如何降級(jí)?

細(xì)心的朋友會(huì)發(fā)現(xiàn)開頭的題綱中有一個(gè)降級(jí)的指向,那么是在什么情況下發(fā)生降級(jí)的呢?

圖片圖片

在能使用記錄鎖或者間隙鎖就能避免幻讀現(xiàn)象的場(chǎng)景下, next-key lock 就會(huì)退化成記錄鎖或間隙鎖。

有以下場(chǎng)景:

唯一索引等值查詢:
1.當(dāng)查詢的記錄是存在的,next-key lock 會(huì)退化成【記錄鎖】 2.當(dāng)查詢的記錄是不存在的,next-key lock 會(huì)退化成【間隙鎖】

非唯一索引等值查詢:
1.當(dāng)查詢的記錄存在時(shí),除了會(huì)加 next-key lock 外,還額外加間隙鎖,也就是會(huì)加兩把鎖。
2.當(dāng)查詢的記錄不存在時(shí),只會(huì)加 next-key lock,然后會(huì)退化為間隙鎖,也就是只會(huì)加一把鎖。

責(zé)任編輯:武曉燕 來(lái)源: 小許code
相關(guān)推薦

2024-05-15 09:23:45

MySQL排他鎖共享鎖

2010-04-22 09:42:00

2025-02-10 09:58:48

2021-09-10 07:59:31

中斷鎖Java多線編程

2024-03-04 00:01:00

鎖表鎖行MySQL

2022-07-12 08:56:18

公平鎖非公平鎖Java

2024-04-03 14:56:12

生成式AI人工智能機(jī)器學(xué)習(xí)

2024-08-26 15:31:55

2022-05-09 07:37:04

Java非公平鎖公平鎖

2024-11-29 07:38:12

MySQL數(shù)據(jù)庫(kù)

2024-05-13 12:44:00

InnodbMySQL行級(jí)鎖

2024-05-15 09:41:22

樂觀鎖編程

2018-07-31 10:10:06

MySQLInnoDB死鎖

2023-12-28 17:33:25

意向鎖MySQL開發(fā)者

2021-11-26 09:53:55

MYSQL開發(fā)數(shù)據(jù)庫(kù)

2019-11-28 16:00:06

重入鎖讀寫鎖樂觀鎖

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2010-05-24 12:50:59

MySQL表級(jí)鎖

2020-10-20 13:50:47

MySQL數(shù)據(jù)庫(kù)

2023-12-06 07:33:20

MySQL鎖事間隙鎖
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)