全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-15 6 分钟 ✍️ juanwangdev

锁等待与超时

锁等待是并发事务竞争资源时的阻塞状态,超时机制防止无限等待。

锁等待机制

锁等待过程

SQL
事务A持有锁
    ↓
事务B请求同一资源锁
    ↓
锁冲突 → 事务B进入等待队列
    ↓
等待事务A释放锁
    ↓
事务A提交 → 事务B获取锁继续执行
    或
超时 → 事务B报错退出

锁等待场景

SQL
-- 事务A(先执行)
START TRANSACTION;
UPDATE orders SET amount = 100 WHERE id = 1;  -- 持有X锁

-- 事务B(等待)
START TRANSACTION;
UPDATE orders SET amount = 200 WHERE id = 1;  -- 等待X锁
-- 阻塞中...

-- 事务A提交
COMMIT;
-- 事务B获取锁继续执行

锁等待超时参数

innodb_lock_wait_timeout

SQL
-- 查看超时设置
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
-- 默认50秒

-- 设置超时时间
SET GLOBAL innodb_lock_wait_timeout = 30;  -- 全局
SET SESSION innodb_lock_wait_timeout = 10; -- 当前会话

-- 配置文件
[mysqld]
innodb_lock_wait_timeout = 30

超时错误处理

SQL
-- 超时后抛出错误
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

-- 应用层处理超时
-- 1. 重试机制
-- 2. 回滚当前事务
-- 3. 记录日志分析

查看锁等待状态

当前锁等待

SQL
-- MySQL 8.0+
SELECT
    OBJECT_NAME,
    LOCK_TYPE,
    LOCK_MODE,
    LOCK_DATA,
    THREAD_ID
FROM performance_schema.data_locks;

-- 查看锁等待关系
SELECT
    requesting_thread_id,
    blocking_thread_id,
    requesting_lock_type,
    blocking_lock_type
FROM performance_schema.data_lock_waits;

-- MySQL 5.7
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
SELECT * FROM information_schema.INNODB_LOCKS;

当前事务状态

SQL
-- 查看当前活跃事务
SELECT
    trx_id,
    trx_state,
    trx_started,
    trx_mysql_thread_id,
    trx_query,
    trx_rows_locked,
    trx_lock_structs
FROM information_schema.INNODB_TRX;

-- trx_state:
-- RUNNING: 正在执行
-- LOCK WAIT: 锁等待中
-- ROLLING BACK: 回滚中

查看阻塞关系

SQL
-- 查找阻塞源头
SELECT
    r.trx_id AS waiting_trx_id,
    r.trx_mysql_thread_id AS waiting_thread,
    r.trx_query AS waiting_query,
    b.trx_id AS blocking_trx_id,
    b.trx_mysql_thread_id AS blocking_thread,
    b.trx_query AS blocking_query
FROM information_schema.INNODB_LOCK_WAITS w
JOIN information_schema.INNODB_TRX r ON w.requesting_trx_id = r.trx_id
JOIN information_schema.INNODB_TRX b ON w.blocking_trx_id = b.trx_id;

死锁与检测

死锁概念

SQL
死锁:两个事务互相等待对方释放锁

事务A:持有资源1锁,等待资源2锁
事务B:持有资源2锁,等待资源1锁
        ↓
互相等待,无法继续
        ↓
需要检测并回滚其中一个事务

死锁示例

SQL
-- 事务A
START TRANSACTION;
UPDATE orders SET amount = 100 WHERE id = 1;  -- X锁(id=1)

-- 事务B
START TRANSACTION;
UPDATE orders SET amount = 200 WHERE id = 2;  -- X锁(id=2)

-- 事务A继续
UPDATE orders SET amount = 300 WHERE id = 2;  -- 等待X锁(id=2)

-- 事务B继续
UPDATE orders SET amount = 400 WHERE id = 1;  -- 等待X锁(id=1)
-- 死锁产生!

死锁检测参数

SQL
-- 死锁检测开关
SHOW VARIABLES LIKE 'innodb_deadlock_detect';
-- 默认ON(开启检测)

-- 关闭死锁检测(高并发场景可能关闭)
SET GLOBAL innodb_deadlock_detect = OFF;
-- 关闭后依赖超时机制

死锁处理

SQL
-- 死锁发生时,InnoDB自动回滚一个事务
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

-- 回滚的是持有锁最少的事务
-- 应用层需重试被回滚的事务

查看死锁日志

SQL
-- 查看最近死锁信息
SHOW ENGINE INNODB STATUS;

-- 在LATEST DEADLOCK部分查看详情
-- 包含:
-- 死锁发生时间
-- 涉及事务信息
-- 持有和等待的锁
-- 被回滚的事务

避免锁等待和死锁

最佳实践

建议说明
保持事务短小减少锁持有时间
按固定顺序访问资源避免循环等待
避免长事务长事务持有锁时间长
合理设计索引行锁而非表锁
设置合理超时防止无限等待

代码示例

SQL
-- ✅ 按固定顺序访问(避免死锁)
START TRANSACTION;
UPDATE orders SET amount = 100 WHERE id = 1;
UPDATE orders SET amount = 200 WHERE id = 2;
COMMIT;

-- ❌ 不同事务顺序相反(可能死锁)
-- 事务A:先1后2
-- 事务B:先2后1

-- ✅ 使用SELECT FOR UPDATE提前锁定
START TRANSACTION;
SELECT * FROM orders WHERE id IN (1, 2) ORDER BY id FOR UPDATE;
UPDATE orders SET amount = 100 WHERE id = 1;
UPDATE orders SET amount = 200 WHERE id = 2;
COMMIT;

监控锁等待指标

状态变量

text
-- 锁等待统计
SHOW STATUS LIKE 'Innodb_row_lock%';

-- Innodb_row_lock_current_waits: 当前等待数
-- Innodb_row_lock_time: 总等待时间(毫秒)
-- Innodb_row_lock_time_avg: 平均等待时间
-- Innodb_row_lock_time_max: 最大等待时间
-- Innodb_row_lock_waits: 等待次数

监控SQL

text
-- 计算平均锁等待时间
SELECT
    Innodb_row_lock_time_avg / 1000 AS avg_lock_wait_sec,
    Innodb_row_lock_waits AS total_waits
FROM (
    SELECT VARIABLE_VALUE AS Innodb_row_lock_time_avg
    FROM information_schema.GLOBAL_STATUS
    WHERE VARIABLE_NAME = 'Innodb_row_lock_time_avg'
) a,
(
    SELECT VARIABLE_VALUE AS Innodb_row_lock_waits
    FROM information_schema.GLOBAL_STATUS
    WHERE VARIABLE_NAME = 'Innodb_row_lock_waits'
) b;

-- 建议:avg_lock_wait_sec < 1秒

要点总结

  • 锁等待超时默认50秒,可按需调整
  • 超时后抛出1205错误,应用层需处理重试
  • 死锁检测默认开启,自动回滚一个事务
  • 通过performance_schema查看锁等待状态
  • 保持事务短小、固定访问顺序避免死锁
  • 监控Innodb_row_lock状态变量评估锁竞争

📝 发现内容有误?点击此处直接编辑

← 上一篇 锁机制概述
下一篇 → MySQL Cluster (NDB Cluster)
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库