目錄
前言
一、什么死鎖
二、產生死鎖的必要條件
三、死鎖發生的具體位置和場景
1. 數據行級別死鎖(最常見)
2. 表級別死鎖
3. 索引間隙鎖死鎖(InnoDB特有)
4. 外鍵約束死鎖
5. 元數據鎖死鎖
6. 內存中的鎖結構死鎖
7. 分布式系統死鎖
如何定位死鎖位置
四、關鍵點總結
前言
????????沒有實踐就沒有發言權,前段時間無聊時,刷到數據庫死鎖相關的。發現自己對這部分有所空缺,查資料進行總結實踐,得出自我觀點。
一、什么死鎖
????????數據庫死鎖是指兩個或多個事務在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,這些事務都將無法繼續執行下去。
二、產生死鎖的必要條件
1. 互斥條件 (Mutual Exclusion)
- 資源一次只能由一個事務獨占使用
- 例如:某一行數據在同一時間只能被一個事務鎖定
2. 占有并等待 (Hold and Wait)
- 事務已經持有至少一個資源,同時又在等待獲取其他事務持有的資源
- 例如:事務A持有記錄1的鎖,同時請求記錄2的鎖
3. 非搶占條件 (No Preemption)
- 已分配給事務的資源不能被強制剝奪,只能由持有者顯式釋放
- 數據庫中的鎖通常不能強行從另一個事務中奪取
4. 循環等待 (Circular Wait)
- 存在一個事務等待環路,每個事務都在等待下一個事務所持有的資源
- ?例如:T1等待T2,T2等待T3,T3等待T1
三、死鎖發生的具體位置和場景
1. 數據行級別死鎖(最常見)
發生位置:
-
表中的特定數據行
-
索引記錄(包括主鍵索引和二級索引)
典型場景:
-- 事務A
UPDATE users SET balance = balance - 100 WHERE id = 1; -- 鎖住id=1的行
UPDATE users SET balance = balance + 100 WHERE id = 2; -- 嘗試鎖住id=2的行(等待)-- 事務B
UPDATE users SET balance = balance - 50 WHERE id = 2; -- 鎖住id=2的行
UPDATE users SET balance = balance + 50 WHERE id = 1; -- 嘗試鎖住id=1的行(等待)
2. 表級別死鎖
發生位置:
-
整個數據表
-
表鎖(如MySQL的MyISAM引擎)
典型場景:
-- 事務A
LOCK TABLE orders WRITE; -- 獲取orders表鎖
-- 嘗試獲取customers表鎖(等待)-- 事務B
LOCK TABLE customers WRITE; -- 獲取customers表鎖
-- 嘗試獲取orders表鎖(等待)
3. 索引間隙鎖死鎖(InnoDB特有)
發生位置:
-
索引記錄之間的間隙
-
不存在的記錄范圍
典型場景:
-- 事務A
SELECT * FROM accounts WHERE id > 100 FOR UPDATE; -- 鎖住id>100的間隙
-- 事務B同時執行
SELECT * FROM accounts WHERE id < 50 FOR UPDATE; -- 鎖住id<50的間隙
-- 當兩個事務嘗試向對方鎖定的間隙插入數據時可能死鎖
4. 外鍵約束死鎖
發生位置:
-
主表和從表的外鍵關系處
-
級聯更新/刪除操作時
典型場景:
-- 事務A
UPDATE parent_table SET id = 2 WHERE id = 1; -- 需要檢查/鎖定子表外鍵
-- 事務B同時
UPDATE child_table SET parent_id = 3 WHERE parent_id = 2; -- 需要檢查/鎖定父表
5. 元數據鎖死鎖
發生位置:
-
數據字典(表結構)
-
在執行DDL和DML并發時
典型場景:
-- 事務A
BEGIN;
SELECT * FROM products; -- 獲取元數據讀鎖
-- 事務B同時執行
ALTER TABLE products ADD COLUMN description TEXT; -- 需要元數據寫鎖(等待)
-- 如果事務A后續嘗試執行需要元數據升級的操作可能死鎖
6. 內存中的鎖結構死鎖
發生位置:
-
數據庫內部鎖管理結構
-
緩沖池中的頁鎖
典型場景:
-
多個事務競爭同一內存頁的訪問權限
-
鎖管理數據結構本身的并發控制問題
7. 分布式系統死鎖
發生位置:
-
跨數據庫節點
-
跨不同服務/微服務
典型場景:
節點A的服務1: 鎖定資源X,請求節點B的資源Y
節點B的服務2: 鎖定資源Y,請求節點A的資源X
四、如何定位死鎖位置
1. MySQL:
SHOW ENGINE INNODB STATUS\G;
-- 查看"LATEST DETECTED DEADLOCK"部分
2. SQL Server:
SELECT * FROM sys.dm_tran_locks;
-- 查看死鎖圖
3. Oracle:
SELECT * FROM v$locked_object;
SELECT * FROM dba_blockers;
五、關鍵點總結
-
死鎖最常發生在行級鎖和間隙鎖上
-
不同數據庫引擎的死鎖熱點位置不同(如InnoDB主要在索引記錄)
-
死鎖不僅發生在數據上,也可能發生在系統內部資源上
-
分布式環境死鎖范圍更廣,更難檢測
那要如何解決上述問題請跳轉:數據庫的死鎖相關(二)