select ... lock in share mode 只阻塞其他事务的 select ... for update 和 update/delete,不阻塞普通 select 或其他共享锁;它允许多个事务同时读,但无法防止并发修改,需配合排他锁或原子更新使用。

SELECT ... LOCK IN SHARE MODE 会阻塞哪些操作
它只阻塞其他事务对同一行执行 SELECT ... FOR UPDATE 或 UPDATE/DELETE,但不阻塞普通 SELECT,也不阻塞其他事务的 SELECT ... LOCK IN SHARE MODE(可共享读锁)。换句话说,它允许多个事务同时加共享锁,但会排队等排他锁。
常见错误现象:以为加了 LOCK IN SHARE MODE 就能防止并发修改,结果两个事务都读到旧值、都执行更新,造成覆盖写。这不是锁失效,而是共享锁本来就不排斥别的共享锁——你需要的是排他锁,或者配合 UPDATE 原子操作。
- 使用场景:适合“读取后校验,再决定是否更新”的流程,比如库存预占(查剩余量 ≥1 → 再扣减),但必须确保后续有
UPDATE或显式等待逻辑 - 注意隔离级别:在
REPEATABLE READ下,该语句会加间隙锁(gap lock),可能意外锁住不存在的行;若只想锁命中行,需确认 where 条件走唯一索引 - 性能影响:锁粒度是行级,但若条件不走索引,会退化为表锁,直接拖慢整个表的写操作
为什么有时候 LOCK IN SHARE MODE 不生效
最常见原因是事务没开启,或自动提交开着:SET autocommit = 1 下,每条语句都是独立事务,锁在语句结束就释放,根本起不到保护作用。
另一个隐蔽坑是:MySQL 的 LOCK IN SHARE MODE 在主从复制中默认是 statement-based(SBR),而共享锁不记录在 binlog,从库不会复现锁行为,导致主从一致性逻辑错乱。如果依赖锁做业务控制,务必用 ROW 格式复制,并确认从库也启用相同隔离级别。
- 检查方式:执行
SELECT @@autocommit和SELECT @@tx_isolation,确保为0和REPEATABLE-READ - 参数差异:
innodb_lock_wait_timeout控制等待超时,默认 50 秒,线上建议设为 5–10 秒,避免长等待拖垮连接池 - 不要和
SELECT ... FOR UPDATE混用在同一事务里,除非明确需要升级锁;否则可能引发死锁,尤其当多行锁顺序不一致时
替代方案:什么时候该用 SELECT FOR UPDATE 而不是 LOCK IN SHARE MODE
当你读完数据后几乎必然要更新(比如查余额 → 扣款),直接用 SELECT ... FOR UPDATE 更安全。它加的是排他锁,天然阻止其他事务读写同一行,省去锁升级步骤,也规避了“先共享再更新”中间的时间窗口。
但要注意:FOR UPDATE 在唯一索引 + 等值查询下只锁匹配行;若用范围条件(如 WHERE amount > 100),同样会加间隙锁,可能比预期锁得更宽。
- 性能对比:两者加锁开销接近,但
FOR UPDATE减少了事务内二次加锁的 round-trip,吞吐略高 - 兼容性影响:MySQL 5.7+ 和 8.0 行为一致;但某些 ORM(如早期 Django)默认不支持
LOCK IN SHARE MODE,却普遍支持FOR UPDATE - 示例:想扣减用户余额且不允许透支,应写
SELECT balance FROM users WHERE id = 123 FOR UPDATE,而不是先SHARE MODE再UPDATE
调试锁冲突:怎么看谁在等哪条锁
别靠猜。直接查 information_schema.INNODB_TRX 和 INNODB_LOCK_WAITS,它们实时反映当前阻塞关系。
典型命令:SELECT * FROM information_schema.INNODB_TRX\G 看正在运行的事务及其状态;再联查 INNODB_LOCK_WAITS 可定位 blocker_trx_id 和被阻塞的 SQL。
- 容易忽略的点:
INNODB_LOCK_WAITS只显示“已形成”的等待,刚发起的锁请求若还没排队成功,不会立刻出现——要结合SHOW ENGINE INNODB STATUS的 LATEST DETECTED DEADLOCK 片段看上下文 - 注意时间字段:
TRX_STARTED是事务开始时间,不是锁申请时间;真正卡住的是TRX_WAITING为 1 的记录 - 路径和配置项:
innodb_status_output_locks需设为ON才能在SHOW ENGINE INNODB STATUS中看到详细锁信息
实际业务中,共享锁的“共享性”常被误读为“安全性”,但它本质是协作机制,不是防护罩。真正防并发写,得靠排他锁、原子更新,或应用层分布式锁兜底。锁本身不解决逻辑问题,只提供同步原语。











