剖析 MySQL InnoDB 共享行锁 (S) & 排他行锁 (X)

MySQL InnoDB 共享行锁(S) & 排他行锁(X)

注意:行锁只在 InnoDB 引擎,并且事务开启下生效;自动提交 autocommit=1 时锁会立刻释放,看不到锁效果

行锁是记录锁,锁住某一行数据,不是锁整张表。

1、共享行锁 S(Shared,读锁)

加锁语法select ... for share;(MySQL8.0,旧版 LOCK IN SHARE MODE

  • 特性:
  1. 多个事务可以同时加S锁(读读兼容)
  2. 如果事务A对一行加S锁,其他事务还可以继续加S锁 ,但不能加X排他锁
  3. S锁事务可以读数据;不能修改这行数据,要修改必须升级为X锁

使用场景

  1. 先读取数据,后续业务要修改,希望防止别人把这条数据删掉/做重大修改,但允许别人读取

举例:订单校验,先查询订单状态,后续要更新订单;不希望别的事务直接更新/删除这条订单,但允许其他业务读取订单信息。

sql 复制代码
begin;
select * from t_order where id=100 for share; -- 加S共享行锁
-- 业务逻辑校验
update t_order set status=2 where id=100; -- 尝试修改,S锁升级X锁,如果此时有其他S锁,会阻塞等待
commit;
  1. 多事务共同读取同一行,数据要保证读取期间不被别的事务改写

适合:数据核对、统计,允许多方读,但禁止别人写。

⚠️ S锁坑点:

如果多个事务同时加S锁,然后都想更新这行,互相等待,直接死锁

事务1:S锁 → 想升级X锁;事务2:S锁 → 想升级X锁;互相阻塞,死锁。

所以业务要更新的场景,更推荐直接用X锁,不要用S锁

2、排他行锁 X(Exclusive,写锁)

加锁语法select ... for update;

DML语句(update / delete / insert会自动给命中行加X排他锁

  • 特性:
  1. 互斥 :一行加了X锁之后,其他事务既不能加S锁,也不能加X锁
  2. 持有X锁的事务,可以读写这行;其他事务读写都会阻塞等待锁释放。

使用场景

  1. 并发更新,防止超卖、数据错乱(最常用)

扣库存:查询库存同时上锁,不允许其他事务修改该行,避免并发超卖

sql 复制代码
begin;
select stock from goods where id=1 for update; -- 加X行锁
update goods set stock = stock -1 where id=1;
commit;
  1. 业务确定接下来就要修改/删除该行,直接上写锁,避免幻读、脏写
  2. delete、update 执行时,InnoDB自动加X行锁,不需要手动写for update。

锁兼容矩阵(重点)

当前持有锁 申请S锁 申请X锁
S锁 ✅ 通过 ❌ 阻塞
X锁 ❌ 阻塞 ❌ 阻塞

对比总结

锁类型 语法 核心特点 适用场景 不适合场景
S共享行锁 select ... for share 允许多个事务读;阻止别人写 多读,短时间校验,允许其他事务读取 后续要更新,多并发更新,容易死锁
X排他行锁 select ... for update/update/delete 独占,别人不能读也不能写 并发修改、扣库存、订单状态变更 大量并发只读场景,会造成大量阻塞

实际业务最佳实践

  1. 绝大多数并发更新场景,直接用 X锁(for update),尽量少用S锁,规避S锁带来的死锁风险。
  2. S锁适合:只做校验读取,确定本事务不会修改该行的场景。
  3. 行锁生效前提:where条件命中索引,如果没走索引,InnoDB会退化成表锁,整张表锁住,性能灾难。
  4. 锁直到事务commit / rollback才释放,事务不要写大业务,尽快提交,减少锁持有时间。

补充区分快照读 vs 当前读

  • 普通select:快照读,不加锁,走MVCC,不受行锁影响,可以读到旧版本数据。
  • for share / for update / update / delete当前读,会真实加行锁。

举个例子:A事务给一行加X锁;B事务普通select依然可以查到数据(MVCC快照),但B执行select ... for update就会阻塞。

相关推荐
Lumistory1 小时前
城市景观亮化设施维护管养的核心痛点与标准化解决方案
数据库·光照贴图
技术长镜头1 小时前
别再只说“走 B+Tree”:一条 SQL 在 InnoDB 中的完整寻址过程
后端·mysql
倒流时光三十年1 小时前
第六阶段 57 · ES|QL 与 SQL API(用 SQL 查 ES)
数据库·sql·elasticsearch
努力进修2 小时前
“数据心脏” 驱动能源自主:国产数据库支撑 Cemsol 实现固井全流程数字化闭环
数据库·人工智能·能源
vHelios2 小时前
SQL不会写?不会找关联表?复杂SQL语句编写逻辑实现思路请查收✉
数据库·sql
DB哥讲数据库3 小时前
【ClickHouse安装教程】从零开始部署高性能列式数据库(附ClickHouse安装包)
数据库·clickhouse
TDengine (老段)3 小时前
TDengine 第三方工具 — Telegraf、Kafka Connect、Flink、Spark
大数据·数据库·物联网·flink·kafka·时序数据库·tdengine
小白勇闯网安圈12 小时前
Django 响应对象、文件上传与类视图
数据库·django·sqlite
努力的小雨13 小时前
同一份 SQL 跑多套环境:Ksql 变量怎么用才安全
数据库