Mysql鎖的型別與簡析

2022-05-10 13:01:37 字數 2589 閱讀 8664

資料庫鎖設計的初衷是處理併發問題。作為多使用者共享的資源,當出現併發訪問的時候,資料庫需要合理地控制資源的訪問規則。而鎖就是用來實現這些訪問規則的重要資料結構。

根據加鎖的範圍,mysql 裡面的鎖大致可以分成全域性鎖、表級鎖和行鎖三類。

全域性鎖

顧名思義,全域性鎖就是對整個資料庫例項加鎖。mysql 提供了乙個加全域性讀鎖的方法,命令是 flush tables with read lock (ftwrl)。當你需要讓整個庫處於唯讀狀態的時候,可以使用這個命令,之後其他執行緒的以下語句會被阻塞:資料更新語句(資料的增刪改)、資料定義語句(包括建表、修改表結構等)和更新類事務的提交語句。

全域性鎖的典型使用場景是,做全庫邏輯備份。也就是把整庫每個表都 select 出來存成文字。

官方自帶的邏輯備份工具是 mysqldump。當 mysqldump 使用引數–single-transaction 的時候,導資料之前就會啟動乙個事務,來確保拿到一致性檢視。而由於 mvcc 的支援,這個過程中資料是可以正常更新的。

你一定在疑惑,有了這個功能,為什麼還需要 ftwrl 呢?一致性讀是好,但前提是引擎要支援這個隔離級別。比如,對於 myisam 這種不支援事務的引擎,如果備份過程中有更新,總是只能取到最新的資料,那麼就破壞了備份的一致性。這時,我們就需要使用 ftwrl 命令了。

所以,single-transaction 方法只適用於所有的表使用事務引擎的庫。如果有的表使用了不支援事務的引擎,那麼備份就只能通過 ftwrl 方法。這往往是 dba 要求業務開發人員使用 innodb 替代 myisam 的原因之一。

表級鎖

mysql 裡面表級別的鎖有兩種:一種是表鎖,一種是元資料鎖(meta data lock,mdl)。

表鎖

表鎖的語法是 lock tables … read/write。與 ftwrl 類似,可以用 unlock tables 主動釋放鎖,也可以在客戶端斷開的時候自動釋放。需要注意,lock tables 語法除了會限制別的執行緒的讀寫外,也限定了本執行緒接下來的操作物件。

在還沒有出現更細粒度的鎖的時候,表鎖是最常用的處理併發的方式。而對於 innodb 這種支援行鎖的引擎,一般不使用 lock tables 命令來控制併發,畢竟鎖住整個表的影響面還是太大。

元資料鎖

mdl 不需要顯式使用,在訪問乙個表的時候會被自動加上。mdl 的作用是,保證讀寫的正確性。你可以想象一下,如果乙個查詢正在遍歷乙個表中的資料,而執行期間另乙個執行緒對這個表結構做變更,刪了一列,那麼查詢執行緒拿到的結果跟表結構對不上,肯定是不行的。

因此,在 mysql 5.5 版本中引入了 mdl,當對乙個表做增刪改查操作的時候,加 mdl 讀鎖;當要對錶做結構變更操作的時候,加 mdl 寫鎖。

需要注意的是:mdl 會直到事務提交才釋放,在做表結構變更的時候,你一定要小心不要導致鎖住線上查詢和更新。

行鎖

mysql 的行鎖是在引擎層由各個引擎自己實現的。但並不是所有的引擎都支援行鎖,比如 myisam 引擎就不支援行鎖。不支援行鎖意味著併發控制只能使用表鎖,對於這種引擎的表,同一張表上任何時刻只能有乙個更新在執行,這就會影響到業務併發度。innodb 是支援行鎖的,這也是 myisam 被 innodb 替代的重要原因之一。

在 innodb 事務中,行鎖是在需要的時候才加上的,但並不是不需要了就立刻釋放,而是要等到事務結束時才釋放。這個就是兩階段鎖協議。

知道了這個設定,對我們使用事務有什麼幫助呢?那就是,如果你的事務中需要鎖多個行,要把最可能造成鎖衝突、最可能影響併發度的鎖盡量往後放。

舉個例子。

從顧客 a 賬戶餘額中扣除電影票價;

給影院 b 的賬戶餘額增加這張電影票價;

記錄一條交易日誌。

也就是說,要完成這個交易,我們需要 update 兩條記錄,並 insert 一條記錄。當然,為了保證交易的原子性,我們要把這三個操作放在乙個事務中。那麼,你會怎樣安排這三個語句在事務中的順序呢?

試想如果同時有另外乙個顧客 c 要在影院 b 買票,那麼這兩個事務衝突的部分就是語句 2 了。因為它們要更新同乙個影院賬戶的餘額,需要修改同一行資料。

根據兩階段鎖協議,不論你怎樣安排語句順序,所有的操作需要的行鎖都是在事務提交的時候才釋放的。所以,如果你把語句 2 安排在最後,比如按照 3、1、2 這樣的順序,那麼影院賬戶餘額這一行的鎖時間就最少。這就最大程度地減少了事務之間的鎖等待,提公升了併發度。

死鎖和死鎖檢測

當併發系統中不同執行緒出現迴圈資源依賴,涉及的執行緒都在等待別的執行緒釋放資源時,就會導致這幾個執行緒都進入無限等待的狀態,稱為死鎖。

這時候,事務 a 在等待事務 b 釋放 id=2 的行鎖,而事務 b 在等待事務 a 釋放 id=1 的行鎖。 事務 a 和事務 b 在互相等待對方的資源釋放,就是進入了死鎖狀態。當出現死鎖以後,有兩種策略:

減少死鎖的主要方向,就是控制訪問相同資源的併發事務量。

MYSQL中的樂觀鎖實現 MVCC 簡析

mvcc即multi version concurrency control,中文翻譯過來叫多版本併發控制。眾所周知,在mysql中,myisam使用的是表鎖,innodb使用的是行鎖。而innodb的事務分為四個隔離級別,其中預設的隔離級別repeatable read需要兩個不同的事務相互之間不...

MYSQL中的樂觀鎖實現 MVCC 簡析

mvcc即multi version concurrency control,中文翻譯過來叫多版本併發控制。眾所周知,在mysql中,myisam使用的是表鎖,innodb使用的是行鎖。而innodb的事務分為四個隔離級別,其中預設的隔離級別repeatable read需要兩個不同的事務相互之間不...

Python原始碼學習 內建型別簡析並簡析int物件

本文環境python2.5系列 參考書籍位於include object.h中 typedef struct object pyobject typedef struct pyvarobject define pyobject head pyobject head extra py ssize t ...