首页/数据/SQL 速查/锁读:SELECT FOR UPDATE / FOR SHARE
变更与事务52 条

锁读:SELECT FOR UPDATE / FOR SHARE

在事务里对行加锁再读写:解决“先查后改”的并发竞争;MySQL 与 PostgreSQL 语法接近,锁强度不同。

SQL 速查数据更新于 2026-10-13

锁读是什么

锁读在事务里先对行加锁再读写,用来解决「先查后改」的并发竞争,典型场景是任务队列里取一条待处理任务并标记为处理中。MySQL 与 PostgreSQL 都支持 SELECT … FOR UPDATE(排他锁)与 FOR SHARE(共享锁);MySQL 8.0 起用 FOR SHARE 取代旧的 LOCK IN SHARE MODE。锁读必须在事务里才有意义,autocommit 下单条语句结束就释放锁。WHERE 条件走不到索引时锁范围会放大,可能把并发写入整体堵住。

基本信息

FOR UPDATE排他锁,其它事务的锁读与写会等待
FOR SHARE共享锁,MySQL 8.0 起取代 LOCK IN SHARE MODE
前提必须在事务内使用,否则锁随语句结束即释放
行锁条件WHERE 要走索引,否则可能升级为更大范围的锁
跳过等待选项MySQL 支持 NOWAIT 与 SKIP LOCKED,PostgreSQL 亦支持
适用平台MySQL 8.0 与 PostgreSQL 语法接近,锁强度细节不同

典型使用场景

  • 任务队列取活:锁住一条待处理任务再改成处理中
  • 库存扣减:先锁住库存行再判断与扣减
  • 账户余额变更:避免并发同时读取同一余额
  • 订单状态流转:保证同一订单不会被两个流程同时改
  • 防止重复执行:锁住任务记录保证幂等
  • 批量取数处理:用 SKIP LOCKED 让多个消费者各取各的

示例

示例
START TRANSACTION;

SELECT * FROM jobs
WHERE state = 'queued'          # 条件要有索引,避免锁范围放大
ORDER BY id
LIMIT 1
FOR UPDATE;                     # 排他锁,锁住这一行

UPDATE jobs SET state = 'running', started_at = NOW()
WHERE id = 100;

COMMIT;                         # 提交后锁释放

-- 多消费者并发取活:跳过已被锁定的行
SELECT * FROM jobs
WHERE state = 'queued' ORDER BY id LIMIT 1
FOR UPDATE SKIP LOCKED;

锁读选项对照

写法锁类型说明
FOR UPDATE排他锁其它事务读写都需等待
FOR SHARE共享锁多个读者可共存,写入需等待
FOR UPDATE NOWAIT排他锁不等待锁被占用立刻报错
FOR UPDATE SKIP LOCKED排他锁跳过已锁定行队列消费常用
LOCK IN SHARE MODE旧共享锁写法MySQL 8.0 起改用 FOR SHARE
锁读之后要在同一事务里完成修改并提交:漏掉 BEGIN 时锁在语句结束就释放,完全防不住并发。
WHERE 条件没有索引时锁定范围可能放大到扫描到的全部行,甚至近似全表;上线前先用执行计划确认走了索引。
SKIP LOCKED 是队列类场景的实用组合:多个消费者并发取任务时各取各的,不会互相等待。

使用要点

  • 锁读与修改必须在同一事务内成对出现
  • WHERE 条件要能走索引,避免锁范围放大
  • 事务保持短:锁住到提交之间的耗时越短越好
  • 队列场景用 SKIP LOCKED 提高并发消费效率
  • 锁等待超时要有兜底:捕获超时错误并重试或降级
  • 定期排查长事务与锁等待,及时发现争用热点

易错点

  • WHERE 条件没有走索引时,锁定范围可能放大到扫描到的全部行,甚至近似全表,先确认执行计划再上线
  • 锁读语句必须在事务里成对使用:漏掉 BEGIN 时锁在语句结束就释放,防不住并发
  • 事务里夹着外部调用,锁被长期持有,其它请求全部排队
  • 多个事务按不同顺序锁同一批行,出现死锁并被数据库回滚其中一个
  • 把 FOR UPDATE 用在只读查询上,白白增加锁竞争与等待

数据来源与参考

  • MySQL 8.0 Reference Manual · Locking Reads
  • PostgreSQL Documentation · SELECT
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌