Skip to content
MySQL 事务、锁与高可用 · 第 1 篇 / 共 6 篇
领域数据与中间件
专题MySQL 专题
当前序列MySQL 事务、锁与高可用
阅读位置第 1 篇 / 共 6 篇当前专题第 2 个序列 / 共 7 个序列

MySQL 事务与锁:隔离级别、MVCC、行锁、间隙锁到底怎么理解

很多人学 MySQL 事务时最容易出现一个问题:

  • 记住了隔离级别名字
  • 但遇到锁等待、死锁、更新冲突时,还是不知道该怎么解释

真正要理解事务和锁,不能只背定义,还要把这些概念串起来:

  • 隔离级别
  • MVCC
  • 当前读
  • 行锁
  • 间隙锁

先说结论

如果从 InnoDB 的实际行为出发,可以先抓住三件事:

  • 普通查询很多时候依赖 MVCC,而不是加锁读
  • 更新类语句最终还是要依赖锁保证并发安全
  • 很多“锁范围比预期大”的问题,都和索引命中情况有关

一、事务到底解决什么

事务最核心的价值不是“能回滚”这么简单,而是:

  • 把一组操作当成一个整体
  • 保证要么都成功,要么都失败
  • 在并发下尽量维持可接受的一致性

二、四种常说的隔离问题

1. 脏读

读到了别的事务还没提交的数据。

2. 不可重复读

同一个事务里前后两次读取同一行,结果不一致。

3. 幻读

同一个事务里按条件查询,两次看到的记录集合不一样。

4. 丢失更新

多个事务写同一份数据,后写覆盖前写。

这些问题不是一定都会发生,而是取决于:

  • 当前隔离级别
  • 读写方式
  • 是否命中锁

三、隔离级别怎么理解更实际

MySQL 常见隔离级别包括:

  • 读未提交
  • 读已提交
  • 可重复读
  • 串行化

InnoDB 默认通常是:

  • 可重复读

但你不能把“可重复读”简单理解成“一切都不会变”,因为真实行为还会受到:

  • MVCC
  • 当前读
  • 锁范围

影响。

四、MVCC 为什么这么重要

很多普通 select 并不会直接给记录加排他锁,而是通过 MVCC 读取某个一致性视图中的版本。

这带来的好处是:

  • 读写冲突减少
  • 普通查询不容易被阻塞

所以很多时候你看到“查询没有被锁住”,不是因为没有并发问题,而是因为它走的是一致性读。

五、什么是当前读

和一致性读相对的,是当前读。

典型包括:

  • select ... for update
  • select ... lock in share mode
  • update
  • delete

这类读更关心“当前最新数据”,所以通常要配合锁来保证并发安全。

六、行锁为什么经常被误解

很多人以为:

  • 执行的是更新某一行
  • 所以一定只锁这一行

但 InnoDB 的锁很多时候是“基于索引”的。

也就是说:

  • 如果没走到合适索引
  • 锁范围就可能放大

这也是很多线上锁冲突的根源。

七、间隙锁和 Next-Key Lock 怎么理解

在可重复读隔离级别下,InnoDB 为了避免某些并发插入带来的幻读问题,会引入:

  • 间隙锁
  • Next-Key Lock

你可以先粗略理解成:

  • 不只锁已有记录
  • 还可能锁住记录之间的区间

这样做的代价就是:

  • 锁冲突有时会比你直觉中更大

八、为什么很多锁问题最终都要看索引

因为 InnoDB 锁往往不是单纯按“SQL 语义的一行”来工作的,而是按:

  • 索引访问路径

来决定锁住哪些记录和范围。

所以如果出现:

  • 锁等待
  • 大面积阻塞
  • 更新冲突异常高

很值得先排查:

  • 条件列是否有索引
  • 是否命中正确索引
  • 是否扫了过大范围

九、死锁应该怎么理解

死锁不是 MySQL 独有问题,而是并发系统里的经典问题。

在数据库里常见原因是:

  • 两个事务持有不同资源
  • 又都在等待对方释放

这时系统会主动检测并回滚其中一个事务。

所以看到死锁时,重点不是只会重试,而是要反推:

  • 访问顺序是否一致
  • 事务是否太大
  • 更新范围是否过宽

十、几个很实用的事务设计原则

1. 事务尽量短

事务越长,持锁时间越长,冲突概率越高。

2. 尽量走索引更新

否则锁范围和扫描范围都可能变大。

3. 先统一访问顺序

多表、多资源更新时尤其重要。

4. 不要把外部调用放进长事务

例如:

  • 事务里做远程调用
  • 事务里做耗时 IO

这会显著放大锁持有时间。

一句话总结

MySQL 事务与锁真正难的地方,不是隔离级别名字,而是要把 MVCC、当前读、索引路径和锁范围放在一起理解。

当你能从“这条 SQL 是怎么被访问和加锁的”去看问题时,很多线上锁等待和死锁现象都会更容易解释。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 顺着当前主线继续读MySQL 死锁怎么排查适合把事务锁、死锁、主从复制、写后读一致性和切换治理串起来看。MySQL 专题 · MySQL 事务、锁与高可用同一序列 · 顺着当前主线继续读MySQL 常见连接与包大小错误排查适合把事务锁、死锁、主从复制、写后读一致性和切换治理串起来看。MySQL 专题 · MySQL 事务、锁与高可用同专题其他序列 · 共享标签:并发autocommit 为什么也会影响锁行为适合把 next-key lock、一致性读、复制延迟和分库分表边界放回同一条一致性主线上判断。MySQL 专题 · MySQL 事务、锁与高可用边界同专题其他序列 · 共享标签:并发next-key lock 到底锁住了什么适合把 next-key lock、一致性读、复制延迟和分库分表边界放回同一条一致性主线上判断。MySQL 专题 · MySQL 事务、锁与高可用边界跨专题关联 · 同场景:基础学习线程池参数怎么配适合把线程池参数、拒绝策略、CompletableFuture 和 ForkJoin 放在一起连续看。Java 专题 · Java 线程池与异步编排跨专题关联 · 同场景:基础学习@Conditional 系列注解怎么配合使用适合把自动装配、条件装配、Profile 和循环依赖放回 Spring Boot 启动过程里理解。Spring 专题 · Spring Boot 启动、装配与配置
继续阅读MySQL 事务、锁与高可用当前序列第 1 篇 / 共 6 篇当前专题第 2 个序列 / 共 7 个序列
往前看
上一序列MySQL 建模与查询优化从第 1 篇开始:MySQL 字段类型怎么选
往后看
下一篇MySQL 死锁怎么排查继续当前序列下一章下一序列MySQL 存储引擎与执行细节从第 1 篇开始:MVCC 和 Read View 怎么理解

把零散经验整理成可查、可复用、可持续更新的企业级知识门户