跳到正文
Elaine Blog
返回

InnoDB 锁、死锁与锁等待

MyBatis、MySQL 与数据架构

InnoDB 所谓“行锁”通常锁的是索引记录或索引范围。SQL 没有合适索引时,扫描范围扩大,锁影响面也可能扩大。死锁无法靠提高超时时间解决,应用必须准备重试。

Table of contents

Open Table of contents

常见锁术语

术语作用
记录锁 Record Lock锁住一条索引记录
间隙锁 Gap Lock锁住两条索引记录之间的范围
临键锁 Next-Key Lock记录锁加前方间隙,用于范围和幻读控制
意向锁 Intention Lock表级标记事务准备在某些记录上加共享/排他锁

普通一致性 SELECT 通常不加记录锁;FOR SHAREFOR UPDATEUPDATEDELETE 属于锁定读写。锁具体覆盖什么取决于隔离级别、索引唯一性和实际扫描范围。

动手制造一个死锁

打开两个 MySQL 客户端,按照事务实验脚本的 A1、B1、A2、B2 顺序执行。两个事务以相反顺序持有并请求订单 1、2,形成等待环。InnoDB 会选择一个事务回滚,让另一个继续。

随后查询:

SHOW ENGINE INNODB STATUS;
SELECT * FROM performance_schema.data_lock_waits;

死锁日志要读出两个事务、已持有锁、等待锁和相关 SQL,不要只复制最后一条报错。

如何减少死锁

让所有流程按同一顺序锁资源;为条件建立合适索引,缩小扫描与持锁集合;拆掉事务中的远程调用;一次处理适量记录;监控死锁率和事务耗时。即便都做到,数据竞争下仍可能死锁。

应用捕获数据库死锁异常后,应回滚并以有限次数、随机退避重试整个事务。只重试失败的最后一条 SQL,可能丢失前面已回滚的步骤。

参考 InnoDB 锁与事务模型

下一步

继续阅读06-11 MVCC、Read View 与一致性读,理解读操作为何常常不必阻塞写操作。


分享这篇文章:

上一篇
ACID 与隔离级别
下一篇
MVCC、Read View 与一致性读