天天看點

mysql資料庫的鎖機制實作_【MySQL入門】之MySQL資料庫的鎖機制(一)

mysql資料庫的鎖機制實作_【MySQL入門】之MySQL資料庫的鎖機制(一)
mysql資料庫的鎖機制實作_【MySQL入門】之MySQL資料庫的鎖機制(一)

一.為什麼要加鎖?

資料庫鎖機制簡單來說,就是資料庫在多事務并發處理時,為了保證資料的一緻性和完整性,資料庫需要合理地控制資源的通路規則。鎖是一種資源,這個資源是和事務關聯在一起的,當某個事務擷取了鎖,在送出或復原之前,就一直持有該鎖。

二.鎖的分類

根據鎖類型劃分

共享鎖(讀鎖):其他事務可以讀,但不能寫。

排他鎖(寫鎖):其他事務不能讀取,也不能寫。

根據加鎖的範圍劃分

全局鎖、表鎖和行鎖三類。

全局鎖

全局鎖就是對整個資料庫執行個體加鎖。當你需要讓整個庫處于隻讀狀态的時候,可以使用這個指令,之後其他線程的以下語句會被阻塞:資料更新語句(資料的增删改)、資料定義語句(包括建表、修改表結構等)和更新類事務的送出語句。全局鎖的典型使用場景是,做全庫邏輯備份。

全局鎖的指令:

Flush tables with read lock

表鎖

MySQL中表級别的鎖有三種:表鎖、意向鎖和中繼資料鎖(meta data lock,MDL)。

表鎖的文法是lock tables…read/write,可以用unlock tables主動釋放鎖,也可以在用戶端斷開的時候自動釋放。

意向鎖主要分為意向共享鎖和意向互斥鎖。

意向共享鎖,事務想要給資料庫某些行加共享鎖,需要先給這張表加上意向共享鎖。

意向互斥鎖,事務想要給資料庫某些行加互斥鎖,需要先給這張表加上意向互斥鎖。

意向鎖主要是解決行鎖和表鎖的沖突問題。假設沒有意向鎖,事務A用行鎖鎖住其中一行,事務B申請表的互斥鎖,然後修改整個表,行鎖和表鎖就會發生沖突,事務B想知道事務A鎖住了哪一行,就需要周遊整張表,這是一個非常耗時的操作。引入意向鎖之後,事務A在加行鎖之前先給表加上意向鎖,這樣如果事務B來擷取表鎖,需要先判斷表上是否有意向鎖,如果有意向鎖則阻塞,等待事務A的鎖釋放。

MDL(metadata lock)是用來保護表的中繼資料資訊的,不需要顯式使用,在通路一個表的時候會被自動加上,MDL的作用是維護資料的一緻性,主要解決DML和DDL操作之間的一緻性問題。

行鎖

MySQL的行鎖是在引擎層由各個引擎自己實作的。但并不是所有的引擎都支援行鎖,比如MyISAM引擎就不支援行鎖。不支援行鎖意味着并發控制隻能使用表鎖,對于這種引擎的表,同一張表上任何時刻隻能有一個更新在執行,這就會影響到業務并發度。InnoDB是支援行鎖的,這也是MyISAM被InnoDB替代的重要原因之一。

行鎖又分為三種,單個行記錄的鎖(record  lock)、間隙鎖(GAP  Lock)、記錄鎖和間隙鎖的組合(next-key  Lock)。

三.MDL鎖

為什麼要引入MDL鎖?

MySQL5.5引入了meta data lock,簡稱MDL鎖,屬于表鎖範疇。MDL的作用是,保證讀寫的正确性。你可以想象一下,如果一個查詢正在周遊一個表中的資料,而執行期間另一個線程對這個表結構做變更,增加了一列,那麼查詢線程拿到的結果跟表結構對不上,肯定是不行的。是以,當對一個表做增删改查操作的時候,加MDL讀鎖;當要對表做結構變更操作的時候,加MDL寫鎖。讀鎖之間不互斥,是以你可以有多個線程同時對一張表增删改查。讀寫鎖之間、寫鎖之間是互斥的,用來保證變更表結構操作的安全性。

中繼資料鎖的使用場景模拟

會話A:

mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> select count(1) from table_test;+----------+| count(1) |+----------+|  2439392 |+----------+1 row in set (7.46 sec)

會話B:

mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> alter table table_test add age int not null;

會話C:

mysql> show processlist;+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+| Id | User | Host      | db     | Command | Time | State                           | Info                                        |+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+| 3 | root | localhost | gmdpdb | Sleep   |  235 |                                 | NULL                                        || 6 | root | localhost | gmdpdb | Sleep   |  138 |                                 | NULL                                        || 7 | root | localhost | gmdpdb | Query   |    3 | Waiting for table metadata lock | alter table table_test add age int not null || 8 | root | localhost | NULL   | Query   |    0 | starting                        | show processlist                            |+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+4 rows in set (0.00 sec)

通過會話C可以看出會話B被阻塞,這是由于會話A拿到了table_test表的中繼資料讀鎖,會話B想申請table_test表的中繼資料寫鎖,由于讀寫鎖互斥,會話B需要等待會話A釋放中繼資料鎖才能執行。

中繼資料鎖可能帶來的問題

Session A

Session B

Session C

begin;

select * from t;

alter table t add age int;

select * from t;

我們可以看到session A會對表t加一個MDL讀鎖,之後session B要加MDL寫鎖會被blocked,因為session A的MDL讀鎖還沒有釋放,而session C要在表t上新申請MDL讀鎖的請求也會被session B阻塞。前面我們說了,所有對表的增删改查操作都需要先申請MDL讀鎖,就都被阻塞,等于這個表現在完全不可讀寫了。

mysql資料庫的鎖機制實作_【MySQL入門】之MySQL資料庫的鎖機制(一)
mysql資料庫的鎖機制實作_【MySQL入門】之MySQL資料庫的鎖機制(一)
mysql資料庫的鎖機制實作_【MySQL入門】之MySQL資料庫的鎖機制(一)

愉快的每一天