MyISAM表级锁无法支撑现代高并发写场景,因其一写即锁全表,连SELECT COUNT(*)也会被阻塞;concurrent_insert=2和low_priority_updates均无效且已弃用;InnoDB行锁依赖索引,无索引则退化为表锁,迁移需严控索引、事务提交与全文索引适配。

MyISAM 表级锁在现代业务中根本扛不住并发写,不是“不够好”,而是设计上就拒绝高并发写场景。
MyISAM 一写就锁全表,连 SELECT COUNT(*) 都会被卡住
只要有一个线程执行 INSERT、UPDATE 或 DELETE,整张表立刻进入写锁状态。其他所有读写请求全部排队等待,包括看似只读的 SELECT COUNT(*) —— 因为 MyISAM 不维护行数元数据,必须扫表统计。
- 常见错误现象:
SHOW PROCESSLIST里大量线程状态为Locked,且持续时间长 -
concurrent_insert=2并不解决本质问题:它只在“纯尾部追加 + 无空洞”的极窄条件下生效;业务表频繁DELETE或UPDATE后必然产生空洞,该参数自动失效 -
low_priority_updates已被 MySQL 8.0+ 标记为 deprecated,启用后写操作让位于读,结果是写超时(Lock wait timeout exceeded)频发,批量任务延迟翻倍
InnoDB 行锁不是“默认生效”,没索引照样锁全表
InnoDB 的行锁实际加在索引记录上,不是加在数据行本身。如果 WHERE 条件没走索引,或走的是非唯一索引且命中多行,就会升级为间隙锁甚至临键锁,锁范围远超预期。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 典型错误:
UPDATE users SET status=1 WHERE name='alice'卡住 →name字段没建索引,触发全表扫描,InnoDB 对整个聚簇索引加锁,等效于表锁 - 验证是否真锁单行:必须用
EXPLAIN确认type是const、eq_ref或ref;唯一索引等值查询(如id=123)才真正只锁那一行 - 事务隔离级别影响锁行为:
READ COMMITTED下不加间隙锁,REPEATABLE READ默认开启,防幻读但扩大锁范围
死锁排查不能只看 PROCESSLIST,得盯 SHOW ENGINE INNODB STATUS
SHOW PROCESSLIST 只能看到“谁卡住了”,但看不出“为什么卡”。真正关键的日志在 SHOW ENGINE INNODB STATUS 输出的 LATEST DETECTED DEADLOCK 段落里。
- 重点看两块:
HOLDS THE LOCK(S)(谁持有什么锁)、WAITING FOR THIS LOCK TO BE GRANTED(谁在等什么锁) -
information_schema.INNODB_TRX只显示当前活跃事务,已回滚的死锁参与者不会出现;日志里的TRANSACTION ID是内部 ID,和trx_id不一致,无法直接关联慢日志 - 避免交叉加锁:多个更新语句尽量按相同顺序访问表和行(比如都先更新
orders再更新inventory),否则极易触发死锁
真正难的不是把 ENGINE=MyISAM 改成 ENGINE=InnoDB,而是迁移后必须确认每条 UPDATE/DELETE 是否命中索引、业务代码是否显式 COMMIT、全文索引分词逻辑是否适配——漏掉任一,线上反而更卡。

















