Mysql—Innodb鎖介紹

一、鎖簡介

鎖這個詞是比較常見的,生活中我們使用鎖來保證一個房間或者一個資源的安全,因爲開鎖需要鑰匙,而鑰匙保存在我們手裏,其他人是無法正常獲取到的。程序中,當我們的程序需要多線程去訪問操作共享資源時,爲了保證一致性,我們需要使用鎖機制來防止併發原因出現的問題,同樣,數據庫會使用這種鎖機制來保證資源的共享安全性,比如當兩個事務都需要更改同一條記錄時,就需要鎖機制來保證一致安全性。

下面根據加鎖的範圍來看下innodb支持的鎖類別:

1.記錄鎖(行鎖)

行級鎖是特定引擎所支持的,比如Innodb是支持行鎖的,這也是它的一個特性,可以在數據記錄級別上鎖,粒度是比較細的,記錄鎖在加鎖類別可以分成兩種鎖:

共享鎖(s鎖):事務可以讀取數據,如果數據加了記錄共享鎖,可以繼續加共享鎖;

排他鎖(x鎖):事務可以更改數據,如果事務加了記錄排他鎖,則不可以在家共享鎖和排他鎖;

兩種鎖的排斥關係如下:

共享鎖(s) 排他鎖(x)

共享鎖(s)

兼容 不兼容

排他鎖(x)

不兼容 不兼容

2.範圍鎖

範圍鎖是指加在區間上的鎖,其鎖定的是一個空間,比如鎖定範圍爲(-∞,1】或(10,30)這種方式,Innodb中這種鎖叫做gap鎖。

間隙鎖(gap lock):工作在事務隔離級別中的RR級別,在索引之間加入鎖,它使得RR級別避免了幻讀;

next key lock:這種鎖描述的在Innodb中會出現行鎖和gap lock結合使用的場景,把這種加鎖方式叫做next key;

3.粗粒度鎖

Innodb還支持粗粒度的鎖,可以建立在表以及段、區、頁上的。其中意向鎖是表級別的鎖,當想要在數據記錄上加x鎖時,需要先在表加上IX鎖。意向鎖之間是兼容的,當我們給表加表鎖的時候,如果沒有意向鎖的話,需要遍歷每一條數據是否有排他鎖,如果沒有才能加表鎖,但是有了意向鎖,直接判斷表上是否有意向排他鎖就可以了。意向鎖是Innodb引擎自我管理的,無需DBA去操作或者管理配置,是一種自我屬性。類別上也是分爲兩種:

意向共享鎖(IS):在數據記錄加排他鎖之前,需要在上級也就是表上加意向排他鎖;

意向排他鎖(IX):在數據記錄加共享鎖之前,需要在上級也就是表上加意向共享鎖;

意向鎖和記錄鎖之間的排斥關係如下:

鎖類別 共享鎖 排他鎖 意向共享鎖 意向排他鎖
共享鎖 兼容 不兼容 兼容 不兼容
排他鎖 不兼容 不兼容 不兼容 不兼容
意向共享鎖 兼容 不兼容 兼容 兼容
意向排他鎖 不兼容 不兼容 兼容 兼容

                                               注:IS或者IX鎖此時是與表級的X鎖或S鎖比較排斥關係

二、加鎖情況

在Innodb引擎中,使用多版本併發控制來處理併發的問題,也就是MVCC(Multi-version Concurrency Control),這個控制方法不僅僅使用在Innodb中,其實已經很多數據庫,以及其他很多的引擎也支持使用了這中控制協議,其最大的有點是讀不加鎖,讀寫不衝突,因此減少了鎖的開銷,提高了讀寫性能,可以理解他是行級鎖的一個變種。

MVCC工作在Innodb的RC和RR事務隔離級別下,因爲RU每次都讀取最新的行,Seriallizable是單線程串行,無需加鎖操作。

在Innodb的MVCC中讀操作分爲兩種:快照讀和當前讀,快照讀讀取的數據可見版本或者歷史版本,無需加鎖操作,當前讀需要讀取數據的最新數據行,並且這些返回的數據行都會加鎖,防止其他事物更改,兩種讀操作包含的sql語句結構:

快照讀:select * from table where ***;簡單的讀取操作;

當前讀:

select * from table where ? lock in share mode;//加S鎖,其他事物可以讀取;

select * from table where ? for update;

insert into table values(...);

update table set ...where ?;

delete from table where ?;

除了第一條加的是S鎖,其他語句都是讀取數據的最新行,並且需要加X鎖,以防止其他事物更改或者讀取。

通過一條update語句,分析sql執行的簡單過程:

1.首先客戶端收到一條sql,客戶端將這個sql發到server層,server經過權限驗證、查詢緩存(開啓)、sql優化、指定執行計劃等步驟之後,會把該sql發送到引擎層;

2.引擎層接收到該sql後,會查找符合該條件的記錄,先去內存查找,如果沒有,則到磁盤讀取放入內存,找到符合條件的記錄返回到server層執行器,並給該記錄執行加鎖操作;

3.執行器根據該返回記錄,生成新的行,調用引擎的寫入接口,將該記錄寫入;

4.引擎層接收到該更新插入請求,更新內存,添加日誌,將更新成功結果返回到server層,一條記錄更新完成;

5.引擎繼續返回滿足條件的行,直到所有滿足條件更新完畢,就會告訴執行器所有記錄更新完成,可以提交;

6.server層發起提交請求,引擎層執行提交操作,完成;

可以看出更新的過程是有一個當前讀加鎖操作,插入記錄如果需要檢查unique key衝突,也需要當前讀的驗證;

三、鎖情況分析

鎖的定義瞭解之後,我們需要知道我們應用中sql執行的內部流程包括加鎖條件 ,這樣纔能有方向的進行優化,提升速度。假如我們分析一條語句的加鎖條件,例如:delete from T1 where id = 10;執行的過程受很多因素參數影響,比如當前引擎的事務隔離級別、id是否有索引,如果有索引,索引的類別是什麼?是主鍵?是唯一索引?下面列出幾種情況,講述鎖的使用方式,可以通過閱讀文章《Mysql—Innodb引擎 索引》瞭解innodb索引信息:

假設有表T1,有字段id,name:

RC級別下:

1.RC級別、id主鍵

id是主鍵,直接在主鍵上加x鎖就可以

2.RC級別、id輔助唯一索引

id爲唯一輔助索引,則需要在輔助索引x鎖,在通過主鍵x鎖,便可確定

3.RC級別、id輔助非唯一索引

將符合條件的非唯一輔助索引上加x鎖、通過輔助索引找到對應的主鍵並加x鎖

4.RC級別、id無索引

id列無索引,則通過全表掃描找到對應的數據記錄,這個過程會使得全部記錄加x鎖。因爲全部加x鎖會嚴重影響性能,後期優化後,在尋找過程中,不符合記錄的記錄會去掉x鎖

RR級別下:

1.RR級別、id主鍵

和RC級別下,id主鍵的情況相同,都是在主鍵上加x鎖;

2.RR級別、id輔助唯一索引

和RC級別下,id輔助唯一索引的情況相同,都是在對應輔助索引和主鍵上加x鎖;

3.RR級別、id輔助非唯一索引

此種情況下會加入gap鎖,加上記錄鎖,也就是在輔助索引上加next key lock,在對應主鍵x加鎖

4.RR級別、id無索引

全變掃描全部x鎖加gap鎖,優化後,不符合記錄的記錄去掉x鎖,也不會加gap鎖;

四、資源地址

官網:https://www.mysql.com

文檔:《Mysql技術內幕-innodb存儲引擎》《高性能Mysql》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章