共享锁(S锁)允许多事务并发读但阻止写,语法为SELECT...FOR SHARE;排他锁(X锁)独占读写,语法为SELECT...FOR UPDATE;二者必须在事务中使用且依赖索引生效,兼容性上S锁与S锁兼容,其余均不兼容。

共享锁(S锁,读锁)和排他锁(X锁,写锁)是 MySQL InnoDB 中最基础、最常用的行级锁类型,直接决定并发读写行为。它们不靠自动触发,必须显式声明,且只在事务中生效。
共享锁怎么加?什么时候用?
共享锁用于“我只读,但要防止别人改”。它允许多个事务同时读同一行,但阻止任何事务修改该行。
- 加锁语法:SELECT * FROM table WHERE id = 1 LOCK IN SHARE MODE; 或更现代的写法:SELECT * FROM table WHERE id = 1 FOR SHARE;
- 加锁后其他事务可以:再加共享锁、执行普通 SELECT(走 MVCC 快照读)
- 加锁后其他事务不可以:加排他锁(FOR UPDATE)、执行 UPDATE/DELETE(会阻塞或超时)
- 典型场景:查库存但暂不扣减,比如“查看商品剩余数量”,需确保查询期间没人下单扣减
排他锁怎么加?什么时候用?
排他锁用于“我要读+改,必须独占”。它排斥一切其他锁,是真正意义上的互斥访问。
- 加锁语法:SELECT * FROM table WHERE id = 1 FOR UPDATE;
- 加锁后其他事务:不能加任何锁(包括共享锁和排他锁),普通 SELECT 仍可读快照,但 UPDATE/DELETE 和带锁查询都会等待或失败
- DML 自动加排他锁:INSERT/UPDATE/DELETE 语句无需手动加锁,InnoDB 默认对涉及行加 X 锁
- 典型场景:转账、扣库存、订单状态更新等需要“读-改-写”原子操作的业务
关键注意事项
这些细节常被忽略,却直接影响锁行为是否符合预期:
- 必须在事务中使用:单独执行 SELECT ... FOR UPDATE 不生效(除非 autocommit=0);记得配 START TRANSACTION 和 COMMIT/ROLLBACK
- 依赖索引才生效行锁:WHERE 条件没走索引(如全表扫描),InnoDB 可能升级为表锁,极大降低并发——务必检查 EXPLAIN
- 锁是逐行加的:即使 SQL 写了 WHERE name = 'xxx',只要 name 没建索引,就可能锁整张表
- 意向锁是隐式配合的:你加 S/X 行锁时,InnoDB 自动在表上加 IS/IX 锁,用于快速判断表级冲突,不用手动干预
共享锁与排他锁兼容性速查
两事务能否同时持有某行的锁,看下表即可快速判断:
| 事务A已持锁 | 事务B请求共享锁(S) | 事务B请求排他锁(X) |
|---|---|---|
| 共享锁(S) | ✅ 兼容(可立即获得) | ❌ 不兼容(等待或失败) |
| 排他锁(X) | ❌ 不兼容 | ❌ 不兼容 |










