mysql行锁是如何实现的_mysql底层机制解析
行锁依赖索引,无索引则退化为表锁;InnoDB通过record lock、gap lock和next-key lock实现行级锁定,其中next-key lock用于防止幻读但易引发死锁。行锁是通过索引实现的,没索引就退化为表锁MySQL 的 InnoDB 行锁(如 SELECT ... FOR UPDATE 或 UPDATE)本身不直接锁“行”,而是锁住索引记录(record lock)或索引间隙(gap lock)。这意味着:如果 WHERE 条件字段没有索引,InnoDB 无法快速定位目标行,只能走全表扫描,此时会为**扫描到的每条记录加锁**,实际效果等同于锁整张表。常见错误现象:UPDATE users SET status=1 WHERE phone='138...' 执行极慢、并发更新卡死——查一下 EXPLAIN,发现 type 是 ALL,key 为 NULL,基本就是这个原因。唯一索引等值查询 → 只锁匹配的那一条索引记录(record lock)普通索引等值查询 → 锁匹配记录 + 对应的主键记录(因为二级索引不存完整行,需回表)范围查询(如 WHERE id > 100)→ 可能触发 gap lock 或 next-key lock,锁住区间而非单行无索引字段 → 全表扫描,逐行加锁,本质是表级争用next-key lock 是行锁+间隙锁的组合,防幻读但易死锁InnoDB 默认事务隔离级别是 REPEATABLE READ,为防止幻读,它用 next-key lock(前开后闭区间)代替单纯的 record lock。比如 SELECT * FROM t WHERE a = 5 FOR UPDATE,若 a 是普通索引且值 5 存在,则锁住的是 (3,5] 或 (5,7] 这样的区间,具体取决于索引结构。这带来两个关键影响:看似只改一行,实际可能锁住一大片相邻记录,阻塞其他事务插入或更新邻近值多个事务按不同顺序访问索引区间时极易形成循环等待 → 死锁。例如事务 A 先锁 (1,3] 再锁 (5,7],事务 B 反过来先锁 (5,7] 再锁 (1,3]使用 SELECT ... LOCK IN SHARE MODE 同样受 next-key lock 影响,不只是 FOR UPDATE显式加锁语句的行为差异:FOR UPDATE vs LOCK IN SHARE MODE两者都走索引才能生效为行锁,但语义和兼容性完全不同: 微软爱写作 微软出品的免费英文写作/辅助/批改/评分工具
