每日一Go·MySQL-5、锁机制全解析

锁机制全解析:表锁 / 行锁 / 间隙锁 / Next-Key Lock 一次讲透.

线上 80% 的数据库性能问题 ,根本原因都不是 SQL,而是:锁冲突 & 锁等待 & 死锁。

真正的 MySQL 高手,拼的不是 SQL 技巧,而是:对锁机制的理解深度。

一、真实业务场景引入

你是否遇到过:

  • 明明走索引,SQL 依然慢?

  • QPS 不高,数据库却经常卡死?

  • 事务频繁阻塞?

  • 线上偶发死锁?

最终排查发现: 锁冲突严重。

问题来了:

  • MySQL 锁了什么?

  • 锁住了哪几行?

  • 锁为什么这么大?

二、MySQL 锁机制整体架构

从层级看,MySQL 锁分为:

  • 表锁(Table Lock)

  • 行锁(Row Lock, InnoDB)

从语义看,锁分为:

  • 共享锁(S Lock)

  • 排他锁(X Lock)

从实现看,InnoDB 行锁细分为:

  • Record Lock(记录锁)

  • Gap Lock(间隙锁)

  • Next-Key Lock(记录锁 + 间隙锁)

三、表锁(Table Lock)

锁住整张表,粒度最大,并发性能最低。

常见实用方式:

cs 复制代码
lock tables user read;
lock tables user write;
  1. 读锁(Read Lock / S)
bash 复制代码
lock tables user read;

效果:

  • 自己可读

  • 别人可读

  • 别人不可写

  1. 写锁(Write Lock / X)
cs 复制代码
lock tables user write;

效果:

  • 自己可读可写

  • 别人不可读不可写

  1. 表锁的应用场景
  • MyISAM 存储引擎

  • 备份

  • 批量离线任务

InnoDB 生产环境: 极少使用表锁

四、行锁(Row Lock)

InnoDB 的核心竞争力:行级锁

特点:

  • 锁粒度小

  • 并发能力强

  1. 行锁本质

InnoDB 的行锁:是加在索引上的,不是直接锁数据行。

  1. 行锁触发条件
sql 复制代码
select * from user where id = 10 for update;

前提:必须命中索引, 否则: 行锁 → 退化为 表级锁扫描

五、共享锁(S Lock) vs 排他锁(X Lock)

|-------|---|---|
| 锁类型 | 读 | 写 |
| 共享锁 S | ✔ | ✘ |
| 排他锁 X | ✔ | ✔ |

  1. 共享锁(S Lock)
cs 复制代码
select * from user where id=1 lock in share mode;

特点:允许多个事务同时读取, 禁止写.

  1. 排他锁(X Lock)
sql 复制代码
select * from user where id=1 for update;

特点: 独占锁, 禁止其他事务读 & 写.

六、Record Lock(记录锁)

锁住单条索引记录

sql 复制代码
select * from user where id = 10 for update;

锁住:id = 10 这一行

七、Gap Lock(间隙锁)

锁住索引之间的"空隙",防止插入新记录

sql 复制代码
select * from user where id > 5 and id < 10 for update;

已有数据:6,8

锁区间:(5,6), (6,8), (8,10)

任何事务都不能插入 7、9

八、Next-Key Lock(终极核心)

Next-Key Lock = Record Lock + Gap Lock

这是 InnoDB 在 RR 隔离级别的默认锁策略

示例拆解:

索引值:1, 5, 10, 20

sql 复制代码
select * from t where id = 10 for update;

加锁区间:(5,10]

不仅锁住 `10`,还锁住 `(5,10)` 整个区间。

九、为什么要有间隙锁 & Next-Key Lock?

  1. 解决幻读
cs 复制代码
事务 A:
select * from t where id between 5 and 10;

事务 B:
insert into t values(7,...);

如果没有间隙锁:A 前后两次读取结果不同 → 幻读

  1. RR 解决方案:MVCC + Next-Key Lock
  • MVCC 解决历史可见性

  • Next-Key Lock 锁住插入区间

从读取 & 写入两个方向同时封死幻读

十、锁与索引的致命关系(生产必懂)

是否命中索引,决定你锁几行。

  1. 命中索引:行锁

  2. 未命中索引:全表扫描 + 行行加锁 → 近似表锁

  3. 线上事故案例

sql 复制代码
update user set status=1 where mobile='13800138000';

如果 `mobile` 没索引:全表扫描 + 每行加锁 → 线上雪崩

十一、当前读 vs 快照读

  1. 快照读(无锁)
sql 复制代码
select * from user where id=1;

走:MVCC

  1. 当前读(加锁)
sql 复制代码
select * from user where id=1 for update;
update user ...
delete user ...

走:锁机制

十二、锁等待 & 死锁简析

  1. 锁等待
  • 事务 A 占锁

  • 事务 B 等锁 → 进入等待队列

可通过下面的语句查看:

css 复制代码
show engine innodb status\G
  1. 死锁经典案例

事务 A:

bash 复制代码
update t set v=1 where id=1;
update t set v=1 where id=2;

事务 B:

bash 复制代码
update t set v=1 where id=2;
update t set v=1 where id=1;

产生:循环等待 → 死锁

InnoDB 自动:回滚代价较小事务

十三、Go 工程实践规范(敲黑板)

  1. 事务中统一访问顺序

    所有业务统一按主键递增顺序访问,从根源杜绝死锁

  2. 事务一定要短

    事务时间 = 锁持有时间

  3. 所有 update / delete 必须走索引

工程规范:禁止非索引条件更新

十四、经典面试题

  1. MySQL 有哪些锁?

答:表锁、行锁、共享锁、排他锁、间隙锁、Next-Key Lock

  1. Next-Key Lock 是什么?

答:记录锁 + 间隙锁,用于解决幻读

  1. 为什么 update 没索引很危险?

答:全表扫描 + 行行加锁 → 并发雪崩

十五、今日总结

  1. 表锁 vs 行锁

  2. 共享锁 vs 排他锁

  3. 间隙锁 & Next-Key Lock

  4. 索引与锁的强耦合关系


源码地址*

1、https://pan.baidu.com/s/1B6pgLWfSgMngVeFfSTcPdg?pwd=jc1s


如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!

相关推荐
Achou.Wang5 小时前
k8s中nginx worker process自动设置
后端·golang
张洛闻Eren5 小时前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
不吃香菜kkk、9 小时前
CI/CD(GitOps)学习与部署手册
运维·云原生·容器·kubernetes·云计算·jenkins·argocd
ChaITSimpleLove9 小时前
云原生性能对决:JDK21虚拟线程+GraalVM vs .NET10/11 技术栈深度对比
微服务·云原生·serverless·graalvm native·native aot·runtime async·.net11/java21
春天花会开1311 天前
Supabase 自部署 Edge Functions 超时从 60s 延长到 360s 完整复盘
运维·云原生
指尖的爷1 天前
ARM 架构 Ubuntu(RK3588/aarch64)go开发环境安装手册
ubuntu·架构·golang
名字还没想好☜1 天前
Go 实现指数退避重试:context 取消、抖动 jitter 与什么时候别重试
后端·golang·go
ysu_03141 天前
【2026】K8s GPU调度空占怎么解?Kueue与Volcano Gang配置
云原生·kubernetes·gpu算力·volcano·ai基础设施·kueue·gang scheduling
Casbin开源社区1 天前
OpenAgent 详解:单二进制自托管 AI Agent 平台,30+ 模型接入、RAG 知识库、MCP 工具调用与 Casbin 工具权限
人工智能·golang·开源