mysql 8.0 并未废弃共享锁,仅将 select ... for share 推为标准语法,lock in share mode 仍完全可用且语义等价;for share 新增 nowait、skip locked、of 等精细控制能力,适用于高并发实时场景。

MySQL 8.0 并没有废弃共享锁,也从未“彻底废弃”LOCK IN SHARE MODE——它只是把 SELECT ... FOR SHARE 作为标准语法推广,并保留旧语法用于向后兼容。
为什么说“废弃共享锁”是误解
共享锁(S 锁)本身是 InnoDB 的核心机制,不可能被废弃。真正变化的是 SQL 语法表达方式:FOR SHARE 是标准化、可扩展的新写法,而 LOCK IN SHARE MODE 是 MySQL 5.7 及更早版本沿用的别名式写法。两者在语义和加锁行为上完全等价,只是前者支持更多选项。
-
FOR SHARE自 MySQL 8.0.1 起正式引入,8.0.22 起权限要求大幅降低(仅需SELECT权限) -
LOCK IN SHARE MODE在所有 8.0 版本中仍完全可用,官方文档明确标注为“deprecated in favor of FOR SHARE”,即“推荐改用”,而非“已移除” - 执行
EXPLAIN FORMAT=tree或查看INFORMATION_SCHEMA.INNODB_TRX,两种写法产生的锁类型、锁粒度、等待行为毫无区别
FOR SHARE 支持哪些 LOCK IN SHARE MODE 不支持的功能
关键差异不在“能不能加共享锁”,而在“怎么控制这个锁”。FOR SHARE 提供了更精细的并发控制能力,旧语法做不到:
-
NOWAIT:请求行锁时若被占用,直接报错ERROR 3572 (HY000),而不是无限等待;LOCK IN SHARE MODE没有对应选项 -
SKIP LOCKED:跳过已被其他事务锁定的行,常用于任务队列消费场景;旧语法不支持该语义 -
OF table_name:显式指定只对某张表加锁(当语句涉及多表 JOIN 时很有用),避免误锁无关表;旧语法无法限定作用范围
例如:SELECT * FROM orders WHERE status = 'pending' FOR SHARE SKIP LOCKED LIMIT 1 是安全取单的经典模式;换成 LOCK IN SHARE MODE 就只能阻塞或超时,无法跳过。
什么时候必须用 FOR SHARE 而不是 LOCK IN SHARE MODE
不是“必须”,而是“值得切换”。如果你遇到以下任一场景,FOR SHARE 就不是可选项,而是实际刚需:
- 业务逻辑要求强实时性,不能接受锁等待(比如秒杀下单前校验库存)→ 用
NOWAIT - 使用基于 SELECT + UPDATE 的分布式任务分发(如订单处理 worker)→ 必须用
SKIP LOCKED避免重复消费 - JOIN 多表且只希望锁定其中一张(比如
SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE ... FOR SHARE OF o)→OF明确收束锁范围 - 运维或安全策略要求最小权限(如只给应用账号
SELECT权限)→FOR SHARE在 8.0.22+ 下无需额外权限,旧语法在同版本下仍需UPDATE或LOCK TABLES
容易忽略的陷阱:自动提交没关,锁根本不会生效
无论用 FOR SHARE 还是 LOCK IN SHARE MODE,只要 autocommit = 1,语句执行完就立刻释放锁——等于没锁。这是线上最常踩的坑。
- 检查当前状态:
SELECT @@autocommit;,返回1表示自动提交开启 - 正确做法:先
SET autocommit = 0;,再BEGIN;,然后执行带FOR SHARE的查询,最后COMMIT或ROLLBACK - 注意:存储过程或应用框架(如 Spring 的
@Transactional)可能隐式管理事务,要确认实际是否进入事务上下文
另一个隐形坑是子查询:外层 FOR SHARE 不会锁内层子查询的表,必须显式在子查询里也写 FOR SHARE,否则锁范围漏掉关键行。











