MyISAM表不会发生死锁,因其仅支持表级锁且无事务机制;阻塞实为锁等待,应使用SHOW PROCESSLIST和SHOW OPEN TABLES排查,优化方向是减少锁表时间或迁移至InnoDB。

MyISAM 表根本不会死锁,别查 SHOW ENGINE INNODB STATUS
MyISAM 不支持事务、没有行级锁、也不维护锁等待队列,它只有表级锁——写操作(INSERT、UPDATE、ALTER TABLE)会独占整张表,其他请求只能排队等。这不是死锁,是单向阻塞。所以:SHOW ENGINE INNODB STATUS 里永远看不到 MyISAM 相关的死锁信息,因为它压根不归 InnoDB 管。
真要排查 MyISAM “卡住”,得看:
-
SHOW PROCESSLIST,找State是Locked或Waiting for table level lock的线程 -
SHOW OPEN TABLES WHERE In_use > 0,确认哪些表正被写锁强占
常见诱因包括:大批次 INSERT 未分批、高峰期执行 ALTER TABLE、SELECT 没加 LOW_PRIORITY 和写操作抢锁。
InnoDB 死锁日志在哪看?关键字段怎么读
死锁发生后,InnoDB 会自动回滚一个事务,并把完整上下文写进 SHOW ENGINE INNODB STATUS 输出的 LATEST DETECTED DEADLOCK 区块。这个输出是唯一权威来源,比错误日志更全。
重点盯三类信息:
-
TRANSACTIONID 和QUERY:哪个事务、执行了哪条 SQL -
holds the lock(s):当前持有哪些锁(比如X locks rec but not gap表示记录锁) -
waiting for this lock:正在等谁的什么锁(比如X locks gap before rec insert intention是插入意向锁冲突)
注意:日志里出现 gap before rec 或 next-key lock 基本指向间隙锁问题;如果两个事务锁的不是同一行但还是死锁,大概率是间隙重叠导致的。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
为什么 UPDATE t1 SET x=1 WHERE id=10 和 UPDATE t1 SET x=2 WHERE id=20 也会死锁
表面看更新不同主键,互不干扰,但实际可能触发间隙锁升级。例如在 RR 隔离级别下:
- 若
id是主键,WHERE id = 10加的是记录锁(安全) - 但若
id是非唯一二级索引,或查询条件没走索引(type: ALL),InnoDB 会锁住扫描范围内的所有间隙,甚至全表 - 更隐蔽的是:并发
INSERT时,两个事务都尝试在同一个间隙插入,各自申请“插入意向锁”,又互相等待对方释放间隙锁 → 死锁闭环形成
所以必须检查 EXPLAIN 输出的 key 和 type 字段,确保 DML 走的是精确索引查找,而不是范围扫描或全表扫。
真正能落地的解决动作有哪些
死锁不能靠“避免”,只能靠“控制循环等待”。以下动作直接对应高频根因:
- 统一加锁顺序:多表更新时,所有事务按固定表名顺序(如先
order再user)执行SELECT ... FOR UPDATE或UPDATE - 缩短事务生命周期:把网络调用、复杂计算、sleep 移出事务体,只留必要 SQL
- 补全索引:对
WHERE、JOIN、ORDER BY字段建联合索引,防止锁扩大 - 业务层加重试:捕获
ERROR 1213 (40001)后自动重试事务(最多 2–3 次),避免用户侧报错 - 高并发写场景慎用 RR:可降为
READ COMMITTED关闭间隙锁(需确认业务能接受幻读)
最常被忽略的一点:死锁日志里的 transaction ID 和 thread_id 可关联到应用日志,从而定位到具体代码路径。不结合业务上下文,光看 SQL 很难判断为何要按那个顺序执行。










