Skip to content

锁与并发控制

1. 这是什么

锁与并发控制描述了 MySQL 在多事务并发下如何保证数据一致性。
这是理解数据库写入冲突、阻塞和死锁的核心。

一句话理解:

  • 锁不是为了“卡住别人”
  • 它是在并发场景下用更少的自由度换正确性

2. 为什么重要

线上系统一旦并发写多起来,锁问题就很容易暴露。
如果不了解锁类型和竞争方式,就很难解释:

  • 更新超时
  • 请求阻塞
  • 死锁回滚

3. 先建立直觉:锁问题通常要和索引一起看

很多人一看到锁,就只盯事务和 SQL。
但真正决定锁范围的,常常还有:

  • 是否命中索引
  • 索引是不是合理

所以锁分析常常要和索引设计一起看。

4. 核心内容

4.1 行锁、表锁

行锁

  • 锁住的是部分记录
  • 并发度通常更高

表锁

  • 锁住整张表
  • 并发自由度更低

学习阶段最重要的不是记定义,而是理解:

  • 锁粒度越大,冲突通常越大

4.2 间隙锁、临键锁

在 InnoDB 里,范围条件下的并发控制不只是“锁某一行”这么简单。
为了防止某些并发插入问题,还会涉及:

  • 间隙锁
  • 临键锁

学习阶段先抓住核心目的即可:

  • 控制范围内并发写入
  • 避免某些幻读风险

4.3 锁等待

锁等待本质上是:

  • 一个事务想拿锁,但锁暂时被别人持有

如果等待时间过长,业务上就会表现成:

  • 请求慢
  • 超时
  • 接口被拖长

4.4 死锁形成机制

死锁通常发生在:

  • 事务 A 持有资源 1,等待资源 2
  • 事务 B 持有资源 2,等待资源 1

数据库通常会检测死锁并:

  • 回滚其中一个事务

所以线上看到死锁错误,不是数据库“坏了”,而是访问顺序和锁路径出了问题。

4.5 并发控制与吞吐权衡

锁更强,一致性更稳;
但锁越多、越久,并发能力通常就越差。

所以数据库并发控制永远是在做权衡:

  • 正确性
  • 吞吐
  • 延迟

5. 学习重点

这一章最重要的是掌握:

  • 数据库锁的目标是保证正确性
  • 不同 SQL 会带来不同锁行为
  • 索引是否命中会直接影响锁范围
  • 死锁要回到访问顺序和索引设计上分析

6. 常见问题

6.1 不清楚更新语句实际锁了什么

这是很多并发写问题的起点。

6.2 忽视索引缺失导致锁范围扩大

索引没设计好时,锁问题常常会被放大。

6.3 遇到死锁只会重试,不会定位原因

重试只是缓解,不是解决。

7. 动手验证

当前环境没有 mysql 客户端,所以这里整理成双会话实验步骤。

7.1 准备测试表

sql
DROP TABLE IF EXISTS lock_demo;

CREATE TABLE lock_demo (
    id BIGINT PRIMARY KEY,
    amount INT NOT NULL
);

INSERT INTO lock_demo (id, amount) VALUES
(1, 100),
(2, 200);

7.2 观察锁等待

会话 A

sql
START TRANSACTION;
UPDATE lock_demo SET amount = amount - 10 WHERE id = 1;

不要提交。

会话 B

sql
START TRANSACTION;
UPDATE lock_demo SET amount = amount + 10 WHERE id = 1;

观察点:

  • 会话 B 会等待

7.3 观察死锁

会话 A

sql
START TRANSACTION;
UPDATE lock_demo SET amount = amount - 10 WHERE id = 1;

会话 B

sql
START TRANSACTION;
UPDATE lock_demo SET amount = amount - 10 WHERE id = 2;

再回会话 A

sql
UPDATE lock_demo SET amount = amount + 10 WHERE id = 2;

再回会话 B

sql
UPDATE lock_demo SET amount = amount + 10 WHERE id = 1;

观察点:

  • 一方会被数据库判定死锁并回滚

8. 练习建议

  • 构造一个简单死锁场景
  • 对比命中索引和不命中索引的加锁差异
  • 总结锁问题排查步骤
  • 用自己的话解释“为什么索引会影响锁范围”

9. 自测问题

  • 为什么索引会影响锁范围?
  • 死锁是怎样形成的?
  • 锁等待为什么会拖慢整个业务链路?
  • 为什么锁问题经常不能只从 SQL 表面看?

10. 自测核对要点

  • 锁粒度和访问路径会直接影响并发能力
  • 索引命中情况常常决定锁范围
  • 死锁本质上是资源循环等待
  • 锁等待会把数据库慢问题传导到整个业务链路