lock in share mode 在读写分离下基本无效,因它仅在主库事务中生效,从库不参与加锁且会静默忽略该提示;真正需要加锁的查询必须强制走主库。

LOCK IN SHARE MODE 不是读写分离场景下的解决方案,它在主库事务中生效,从库不参与加锁,用错地方会导致一致性假象。
为什么 LOCK IN SHARE MODE 在读写分离下基本无效
读写分离本质是主库写、从库读,而 LOCK IN SHARE MODE 是 InnoDB 行锁机制,只在当前连接的存储引擎实例上起作用。从库(尤其是异步复制)没有事务上下文,也不执行加锁逻辑——你连到从库执行 SELECT ... LOCK IN SHARE MODE,MySQL 会静默忽略锁提示(5.7+ 版本返回警告,8.0 默认禁用),根本不会加任何锁。
常见错误现象:
- 应用配置了读写分离,但把校验逻辑发到了从库,执行
SELECT * FROM stock WHERE id = 123 LOCK IN SHARE MODE→ 实际没锁,其他事务立刻能改主库同一行 - 主库事务中用了
LOCK IN SHARE MODE,但从库延迟导致读取到旧值,业务误判后发起更新,引发超卖
真正需要加锁的查询必须走主库
凡涉及“读-判断-后续可能更新”的一致性要求(比如余额校验、库存预占),所有带 LOCK IN SHARE MODE 或 SELECT FOR UPDATE 的语句,必须显式路由到主库。不能依赖中间件自动识别或注释提示。
实操建议:
- 在应用层明确区分:读请求走从库(无锁普通 SELECT),一致性校验类读请求强制走主库
- 使用
BEGIN显式开启事务,再执行SELECT ... LOCK IN SHARE MODE,否则锁在语句结束即释放(READ COMMITTED 下尤其明显) - 确认 WHERE 条件命中索引:用
EXPLAIN检查type是const或ref,key显示具体索引名;否则退化为表锁,主库性能直接受损
读写分离下想保一致性,得换思路
LOCK IN SHARE MODE 解决的是单实例事务内并发控制,不是跨主从的数据同步问题。读写分离场景下的一致性缺口,根源在复制延迟和最终一致性模型。
可选路径:
- 关键路径强制读主:如订单创建、支付校验等,跳过从库,直接连主库做带锁查询 + 更新
- 引入 GTID +
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(MySQL 5.7.6+),让从库同步到指定事务后再读,但有性能代价 - 业务层用版本号(
version字段)+ 乐观锁更新,避免锁竞争,适合读多写少且能容忍重试的场景
最容易被忽略的点:隔离级别与锁生命周期不匹配
很多人开了事务、加了 LOCK IN SHARE MODE,却在 READ COMMITTED 级别下以为锁能撑到事务结束——其实它只锁住当前语句读到的行,语句一结束就释放。真要锁到 COMMIT,必须用 REPEATABLE READ(InnoDB 默认),否则两个事务可能同时读到同一行旧值,都通过校验,然后都去扣减,结果超发。
所以不是“加了锁就行”,而是“锁在哪一级别下持续多久”决定了它是否真能拦住并发修改。这点在主库上都容易翻车,放到读写分离里只会更隐蔽。











