MySQL鎖(1):MySQL全局鎖和表鎖

鎖的概念

鎖用於協調多個客戶端對同一數據的併發訪問,保證併發訪問時數據的有效性和一致性。

MySQL的鎖分爲全局鎖、表鎖和行鎖。

數據準備

創建一個表格,對後續鎖的使用演示做準備。

CREATE TABLE t (
  id int(11) NOT NULL AUTO_INCREMENT,
  a int(11) NOT NULL,
  b int(11) NOT NULL,
  PRIMARY KEY (id),
  KEY idx_a (a)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

insert into t(a,b) values(1,1);

創建表格t,插入一行數據。

全局鎖

全局鎖會關閉所有打開的表並使用全局鎖鎖定數據庫中全部表格。所有表都處於只讀狀態,任何數據、字段的更新都會被阻塞。

一般在數據庫備份過程中會使用到全局鎖,如使用mysqldump命令。整個備份過程中,庫都是隻讀的。不過該命令存在參數--single-transaction,可在事務中創建一致性快照,增加該參數後在數據備份過程中可以對數據進行更新。

對庫中所有表進行鎖定和解鎖的命令如下,

# 全局讀鎖鎖定
flush tables with read lock;

# 全局讀鎖解鎖
unlock tables;

全局鎖實驗,

session1 session2
flush tables with read lock;
select * from t; (正常返回結果) select * from t; (正常返回結果)
insert into t(a, b) values(2, 2); (報錯) insert into t(a, b) values(2, 2); (等待)
unlock tables; 解鎖後上方insert語句執行成功

當全局讀鎖上鎖後,所有表變爲只讀狀態,數據更新或字段更新都會被阻塞

表鎖和元數據鎖

1)表鎖

表鎖使用場景及分類

表鎖使用場景:

  1. 事務中需要對某張大表內的大部分或全部數據進行更新。此時如果使用行鎖,會引發低效、衝突等情況,而使用表鎖可以提升性能。
  2. 事務涉及多個表,比較複雜且容易導致死鎖,考慮使用表鎖能夠避免死鎖

表鎖又分爲表讀鎖表寫鎖,對二者的使用進行說明,

表鎖上鎖命令

對之前構建的表t上表讀鎖和表寫鎖,

# 表讀鎖
lock tables t read;

# 表寫鎖
lock tables t write;

表讀鎖使用

session1 session2
lock table t read;
select id, a, b from t limit 1; (正常返回結果) select id, a, b from t limit 1; (正常返回結果)
insert into t(a, b) values(3, 4); (報錯) insert into t(a, b) values(3, 4); (阻塞)
unlock tables; 上方阻塞語句執行成功

表寫鎖使用

session1 session2
lock table t write;
select id, a, b from t limit 1; (正常返回結果) select id, a, b from t limit 1; (阻塞)
unlock tables; 上方阻塞語句執行成功
lock table t write;
delete from t limit 1; (正常刪除記錄) delete from t limit 1; (阻塞)
unlock tables; 上方阻塞語句執行成功

表鎖使用總結

鎖類型 當前session讀 其餘session讀 當前session寫 其餘session寫
表讀鎖 可讀 可讀 不可寫,報錯 不可寫,阻塞
表寫鎖 可讀 不可讀,阻塞 可寫 不可寫,阻塞

2)元數據鎖(MDL)

元數據鎖相關概念

MySQL中DDL(數據定義語言)不屬於事務範疇,當DDL與事務併發時會出現事務特性被破壞、binlog順序錯亂等bug。從MySQL 5.5.3版本後引入元數據鎖解決事務與DDL並行時數據不一致的問題。

概念辨析

  • DML
    數據操縱語言,用於查詢和修改數據,如insert新增記錄、update更新原有記錄、delete刪除原有記錄和select:查詢
  • DDL
    用於定義數據庫的結構,比如創建,修改刪除數據庫對象,create table … 創建表、drop table… 刪除表、create index…創建索引、drop index …刪除索引和alter table…更改表結構,增加,刪除列,修改列的數據類型,長度等;

每執行一條DML、DDL語句時都會申請MDL鎖,DML操作需要MDL讀鎖,DDL操作需要MDL寫鎖(MDL加鎖過程是系統自動控制,無法直接干預,讀讀共享,讀寫互斥,寫寫互斥)

MDL的存在可能導致長時間所等待,如果該表是查詢頻繁的表,很可能算時間內數據庫連接數就被打滿

明確DDL操作,

操作 說明
create database 庫名; 創建數據庫
drop database 庫名; 刪除數據庫
show databases; 查看MySQL下所有的庫
desc 表名; 查看錶中的字段
rename table 舊錶名 to 新表名; 對已經存在的表進行重命名
alter table 表名 add 字段名 數據類型; 向已存在的表中添加字段信息
alter table 表名 drop 被刪除的字段名; 刪除指定表中的指定字段
alter table 表名 change 舊字段名 新字段名 新字段類型; 對錶中字段進行重命名
alter table 表名 engine=新引擎名; 更改表的存儲引擎
alter table 表名 drop foreign key 外鍵名; 刪除外鍵約束

元數據鎖阻塞示例

MDL引發阻塞演示,假設四個語句先後執行,session A的語句執行過程需要一段時間,
image

爲什麼C等待拿鎖之後,D也會阻塞?其實這裏並沒有解釋清楚。因爲如果按併發理解的話,C,D應當是同等級,都有可能拿到鎖的。但C寫鎖與sessionA的讀鎖互斥,D讀鎖sessionA與不互斥,這樣的話就跟上圖所述相悖了。

image
申請MDL鎖的操作會形成一個隊列,隊列中寫鎖獲取優先級高於讀鎖。一旦出現寫鎖等待,不但當前操作會被阻塞,同時還會阻塞後續該表的所有操作。事務一旦申請到MDL鎖後,直到事務執行完纔會將鎖釋放。

這樣就能解釋通爲什麼session C被阻塞後,session D也運行不了的原因了。

online DDL插隊現象

結合上面的表格進行試驗,實際操作過程中會出現這樣的現象,
在這裏插入圖片描述
這個問題就要涉及到online DDL。由於DDL讀寫互斥,嚴重影響性能,於是MySQL推出了全新的online DDL概念,即通過,

  1. 拿MDL寫鎖
  2. 降級成MDL讀鎖
  3. 真正做DDL
  4. 升級成MDL寫鎖
  5. 釋放MDL鎖

具體圖示如下,
image
該部分內容參考博文

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