首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 死鎖原理與避坑實戰:從「王二與時光老人」的故事看懂循環等待

     編輯:MySQL 綜合教學

前言:死鎖名如其意,卻常被誤解

「死鎖」二字直觀呈現「雙方互相持有對方需要的鎖,陷入無限等待」。但實戰中,很多開發者只知 ERROR 1213,不知其然更不知其所以然。本文結合 InnoDB 行鎖機制,用一個「王二不想讓王一、王三變老」的趣味場景,帶你透過現象看本質,並給出避免死鎖的工程化建議。

一、經典死鎖場景重現

兩個事務,交叉更新兩行資料

-- 事務 A(王二視角:想把王一鎖定 18 歲、王三鎖定 29 歲)
START TRANSACTION;
UPDATE girl SET age=18 WHERE id=2;  -- 鎖住 id=2
UPDATE girl SET age=29 WHERE id=1;  -- 試圖鎖 id=1,被事務 B 持有 → 等待
COMMIT;

-- 事務 B(時光老人視角:堅持王一 19 歲、王三 30 歲)
START TRANSACTION;
UPDATE girl SET age=19 WHERE id=1;  -- 鎖住 id=1
UPDATE girl SET age=30 WHERE id=2;  -- 試圖鎖 id=2,被事務 A 持有 → 等待
COMMIT;

時序圖解析

時光老人 (事務 B)王二 (事務 A)
START TRANSACTION;START TRANSACTION;
UPDATE ... id=1; ✓ 鎖住 id=1
UPDATE ... id=2; ✓ 鎖住 id=2
UPDATE ... id=2; ✗ 等待鎖
UPDATE ... id=1; ✗ 等待鎖
循環等待形成 → InnoDB 偵測死鎖 → 回滾其中一個事務(通常是持有較少鎖、權重較低者)
[Err] 1213 - Deadlock found when trying to get lock; try restarting transaction

二、InnoDB 死鎖偵測與處理機制

  • Wait-for Graph:InnoDB 維護等待圖,定期檢測環路。
  • 受害者選擇:傾向回滾 修改行數較少、持有鎖時間較短、權重較低 的事務。
  • 立即返回錯誤:不等待 innodb_lock_wait_timeout,直接拋 1213。
  • 應用層重試:捕獲 1213 後 完整重試整個事務(非單條 SQL),並建議加指數退避。

三、如何避免死鎖?工程化四大鐵律

  1. 統一資源訪問順序(本文核心):
    兩事務若都按 id=1 → id=2 順序更新,第二個事務只會在第一條 UPDATE id=1 等待行鎖,不會形成循環。
    -- 統一順序後
        -- 事務 A
        UPDATE girl SET age=18 WHERE id=1;
        UPDATE girl SET age=29 WHERE id=2;
        -- 事務 B
        UPDATE girl SET age=19 WHERE id=1;  -- 等待 A 釋放 id=1
        UPDATE girl SET age=30 WHERE id=2;  -- 順利拿到 id=2
  2. 縮短事務長度:少做業務邏輯、少查遠端 RPC、索引命中精準(減少掃描行 → 減少鎖行)。
  3. 合理隔離級別:READ COMMITTED + innodb_locks_unsafe_for_binlog=1(或 5.7+ 默認)可減少間隙鎖,降低死鎖概率,但需評估幻讀風險。
  4. 應用層排隊/分佈式鎖:極高併發熱點資源(如扣庫存),用 Redis 分佈式鎖或單機隊列串行化,根源上消除併發衝突。

四、死鎖排查實戰清單

  1. SHOW ENGINE INNODB STATUS\G 查看 LATEST DETECTED DEADLOCK 區塊(含雙方 SQL、持有鎖、等待鎖)。
  2. 開啟 innodb_print_all_deadlocks=ON(5.6.2+)將死鎖寫入錯誤日誌,便於事後分析。
  3. 結合 performance_schema.data_locks、data_lock_waits(8.0+)實時監控鎖等待鏈。

結語

死鎖本質是「無序併發」產物。統一訪問順序、縮短事務、選對隔離級別、熱點資源上鎖 四招組合拳,能解決 95% 以上死鎖場景。下次見到 ERROR 1213,別慌——先看 SHOW ENGINE INNODB STATUS,再按圖索驥改順序、加索引、或上分佈式鎖,問題迎刃而解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved