LOCK IN SHARE MODE 不能防止脏读,它只防止其他事务修改已读数据;防脏读靠的是事务隔离级别(如READ COMMITTED)和MVCC机制,而非共享锁本身。

Lock IN SHARE MODE 不能防止脏读,它只防写冲突
直接说结论:LOCK IN SHARE MODE 不是用来防脏读的。它加的是共享锁(S 锁),允许其他事务并发读,但会阻塞其他事务对同一行执行 UPDATE、DELETE 或 SELECT FOR UPDATE —— 也就是说,它防的是「别人改我刚读过的数据」,而不是「我读到别人还没提交的数据」。
脏读的本质是读到了未提交的变更。而 LOCK IN SHARE MODE 并不改变事务的隔离级别,也不强制让当前事务「只看已提交版本」。如果当前会话隔离级别仍是 READ UNCOMMITTED,那即使加了 LOCK IN SHARE MODE,照样可能读到脏数据。
真正起作用的是隔离级别本身。InnoDB 的 READ COMMITTED 和 REPEATABLE READ 都靠 MVCC 实现一致性读,天然屏蔽未提交数据 —— 这才是防脏读的主力。
什么时候该用 LOCK IN SHARE MODE
它的典型用途是:需要确保自己读到的数据,在后续操作中不会被别人覆盖,且你**不打算自己修改它**,只是要基于它做判断或关联查询。
- 比如库存校验后,仅记录日志或生成报表,不扣减;
- 读取用户配置后,用于下游服务路由,不更新配置本身;
- 多个服务并行读取同一个状态码表,但要避免在读期间被 DDL 修改(注意:DDL 受 MDL 锁控制,不是这个锁管的)。
这时 LOCK IN SHARE MODE 能防止其他事务在你读完后立刻 UPDATE 同一行,造成你依据过期快照做决策。但它不保证你读到的就是最新已提交值 —— 因为 MVCC 快照已在事务首次 SELECT 时确定。
为什么容易误以为它能防脏读
常见混淆点有三个:
- 把「加锁等待」当成「自动读已提交版本」:如果另一事务正持有 X 锁未提交,
SELECT ... LOCK IN SHARE MODE会阻塞,直到对方提交或回滚;一旦释放锁,你读到的是对方提交后的值 —— 但这只是巧合,不是机制保障; - 混用了
SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE:后者加 X 锁,阻塞所有并发读写,常用于「读-改」闭环,看起来更“安全”,但防脏读的功劳仍属于隔离级别; - 测试环境默认隔离级别是
REPEATABLE READ,本身就防脏读,误把隔离级别功劳记在锁上。
正确组合:隔离级别 + 显式锁才可靠
若业务真需要强一致性读(比如金融类核对),推荐组合:
- 会话级设为
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED(避免长事务拖慢 MVCC 清理); - 关键读操作用
SELECT ... FOR UPDATE,哪怕后续不改,也确保读到的是最新已提交版本,并阻止别人并发改; - 避免在
REPEATABLE READ下依赖LOCK IN SHARE MODE做实时性判断——它的快照可能早已滞后。
最易被忽略的一点:LOCK IN SHARE MODE 对 INSERT 不起作用,也不阻止幻读;想锁住范围(比如防止新插入满足条件的行),得靠 SELECT ... FOR UPDATE 配合索引使用 Next-Key Lock。


















