MySQL全域性鎖、表鎖以及行鎖

songbill發表於2019-02-11

1. 系統版本

MySQL 5.7.25 ubuntu 16.04

2. 全域性鎖

全域性鎖即對整個資料庫例項加鎖,使得整個庫處於只讀狀態,會阻塞DML和DDL語句。
使用如下命令(簡稱FTWRL)可為資料庫加全域性鎖:
flush tables with read lock;
釋放全域性鎖命令如下:
unlock tables;
此外,在客戶端異常斷開後,全域性鎖會自動釋放。

3. 表級鎖

3.1 表鎖

表鎖用於用於為單個表加鎖,表鎖的型別分為讀鎖和寫鎖。

3.1.1 加表鎖的命令

lock tables tb_name read/write;

3.1.2 釋放鎖的命令

unlock tables;

3.1.3表鎖對執行緒的阻塞作用

當前執行緒(假設為執行緒A)對錶加表鎖後:
(1)不能對沒有加鎖的表執行DML和DDL語句;
(2)只能讀加了read表鎖的表;
(3)能讀寫加了write表鎖的表。
線上程A沒有釋放表所前,對於後續的執行緒B:
(1)無法讀寫由其他執行緒(此處為執行緒A)加了write表鎖的表;
(2)可讀但無法寫其他執行緒(此處為執行緒A)加了read表鎖的表;
(3)可讀寫沒有加表鎖的表。

3.2 後設資料鎖

後設資料鎖(meta data lock 簡稱MDL) 用於確保事務執行過程中表結構的穩定。MDL在MySQL 5.5中加入。MDL會在訪問一個表時自動被加上。MDL分為寫鎖和讀鎖。

3.2.1 MDL讀鎖

對一個表執行DML語句時,會加上MDL讀鎖。MDL讀鎖之間不互斥。

3.2.2 MDL寫鎖

對一個表執行DDL語句時,會加上MDL寫鎖。MDL寫鎖和MDL讀鎖之間、MDL寫鎖之間互斥。例如,如果有兩個執行緒要同時給一個表加欄位,其中一個要等另一個執行完方可執行。

4. 行鎖

故名思議,行鎖即對行資料行進行加鎖。行鎖在引擎層由n各個資料庫引進行擎獨自實現。因此,如MyISAM沒有行鎖,InnoDB則有行鎖。

5 兩階段鎖協議及死鎖

兩階段鎖協議能提高資料庫的事務處理效率。結合MVCC(多版本併發控制),能提高資料庫的併發效能。但兩階段協議也形成了造成死鎖的可能性,也為資料庫帶來為解決死鎖問題而產生的額外效能開銷甚至是資料庫崩潰。
以下說明基於MySQL的InnoDB引擎。

5.1 併發控制

併發控制主要有兩種方式:鎖和多版本併發控制(MVCC)。

5.1.1 鎖

為事務所需涉及的表加上鎖(為只需獲資料的共享鎖,為增刪改資料的表加上排他鎖),確保事務序列化,確保資料的正確性。但這影響了資料庫的併發效能。

5.1.2 MVCC(多版本併發控制)

MVCC為資料庫的併發效能提供了高效的解決方案。
InnoDB的MVCC的實現方式為為每一個事務賦予一個自增且唯一的transaction ID。同時為涉及到事務增刪改的資料行形成一個新版本,同時賦這個新版本一個row trx_id,row trx_id的值和對應事務的transaction ID值相同。
在事務開始執行的時候,資料庫會對整個庫建立一個檢視,對於在檢視建時未提交的行數版本,該檢視不可見。
注意,對於已經建立但未提交的資料版本,視會通過row trx_id以及undo log回滾資料行之前已提交的版本。

5.2兩階段鎖協議(Two-Phase Locking,2PL)

兩階段鎖協議指的是事務的執行分為兩個階段,分別為擴充套件階段(此階段只能建立鎖而不能釋放鎖,即需要加鎖的時候才加鎖)以及收階段只能釋而不加鎖)。
兩階段協保證了多個事務在併發的情況下等同於序列的執行,即事務的隔離性。

5.2 死鎖形成原因

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

5.3 死鎖解決機制

(1)超時
直接進入等待,直到超時。這個超時時間可以通過引數innodb_lock_wait_timeout 來設定。
(2)死鎖主動檢查
發起死鎖檢測,發現死鎖後,主動回滾死鎖鏈條中的某一個事務,讓其他事務得以繼續執行。將引數 innodb_deadlock_detect 設定為on,表示開啟死鎖檢測。
注意,死鎖檢查會消耗額外資源,若併發的線過多,則有可能由死鎖檢測而消耗過多資源而導資料庫崩潰。


相關文章