innodb默认行锁、myisam仅支持表锁是引擎底层结构决定的硬性差异:innodb行锁作用于索引记录,需where命中索引才生效;未走索引则全表扫描并逐行加锁,等效表锁;myisam无事务与行定位能力,所有写操作自动加表级写锁,语句结束即释放。

InnoDB 默认走行锁,MyISAM 只能用表锁——这不是配置问题,是引擎底层结构决定的硬性差异。
InnoDB 的行锁怎么生效
行锁实际锁的是索引记录,不是“数据行”本身。只有 WHERE 条件命中索引(主键、唯一索引或普通索引),才能精准定位并加锁。
- 条件没走索引(比如对无索引字段查询、status+0 = 1、DATE(created_at) = '2025-01-01'、name LIKE '%abc'),会全表扫描,逐行加记录锁+间隙锁,效果等同于锁整张表
- 范围查询(如 WHERE age > 25)可能触发间隙锁或临键锁,锁定索引区间,连不相关的行也可能被阻塞
- UPDATE/DELETE 自动加排他锁(X锁);SELECT 需显式写 FOR UPDATE 或 LOCK IN SHARE MODE 才加锁
- 锁在事务提交或回滚后释放;长事务会让锁持有更久,增加冲突概率
MyISAM 的表锁怎么生效
MyISAM 没有事务,也没有行粒度寻址能力,所有写操作(INSERT/UPDATE/DELETE)执行前自动加表级写锁,语句结束立即释放。
- SELECT 自动加读锁(READ LOCAL),允许其他 INSERT 并发追加,但会阻塞所有 UPDATE/DELETE 和显式 WRITE 锁
- 写锁期间,其他会话对该表的任何读写(包括 SELECT)都会等待,直到当前语句完成
- 想延长锁期,只能用 LOCK TABLES t WRITE 显式加锁,再手动 UNLOCK TABLES
- 不存在“锁某一行”的概念——哪怕只更新 id = 1,整张表也进不了其他写操作
怎么验证锁是否按预期工作
必须开两个独立 MySQL 连接(不同 CONNECTION_ID),单个会话看不到阻塞效果。
- InnoDB 验证:会话 A 执行 UPDATE t SET x=1 WHERE id=1 后不提交;会话 B 更新 id=2 能立刻返回,更新 id=1 会卡住
- MyISAM 验证:会话 A 执行 LOCK TABLES t WRITE;会话 B 对 t 做任何 SELECT/INSERT/UPDATE 都会处于 Waiting for table level lock
- 查执行计划:用 EXPLAIN 看 type 是否为 ALL/index、key 是否为 NULL,确认是否真的走了索引
- 看状态:SHOW PROCESSLIST 中状态为 Locked(InnoDB 行锁争用)或 Waiting for table level lock(MyISAM)是关键线索
什么时候 InnoDB 也会锁整张表
不是引擎“降级”,而是 SQL 写法导致它无法做行级定位。
- WHERE 条件未命中任何索引,触发全表扫描 + 逐行加锁
- 更新涉及二级索引字段,且该索引未覆盖查询所需列,需回表,可能扩大锁范围
- 显式执行 LOCK TABLES ... WRITE,或执行 DDL(如 ALTER TABLE),会强制加表级元数据锁(MDL)
- 大范围更新(如没有 WHERE 的 UPDATE)或优化器预估扫描行数占比过高,也可能退化为表锁逻辑











