tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 设计相关

  • 运行相关

    • 常用命令跟重要命令
    • MySql中的各种锁
    • 数据库出现死锁如何排查解决
    • MySql中的MVCC和当前读、快照读
      • MVCC的作用
        • 总结
        • 快照读和当前读
        • 快照读
        • 当前读
        • 对比总结
        • 解决的问题
        • 实际应用场景
      • MVCC实现机制
        • 实现原理
      • MVCC到底解决了幻读没有
        • 但MVCC+间隙锁解决了
    • 几种count的性能比较
  • 事务相关

  • 表设计实战系列

  • 分库分表

  • 框架使用

  • 常用sql跟关键字

  • 安装与卸载相关

  • 《MySql》笔记
  • 运行相关
EffectTang
2025-03-12
目录

MySql中的MVCC和当前读、快照读

# MySql中的MVCC和当前读、快照读

# MVCC的作用

想到并发控制,很多人第一反应就是加锁,的确,加锁确实是解决并发问题最常见的方案。但是,其实除了加锁以外,在数据库领域,还有一种无锁的方案可以来实现并发控制,那就是大名鼎鼎的MVCC(Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC 是通过数据行的多个版本管理来MVCC实现数据库的并发控制。

这项技术使得在InnopB的事务隔离级别下执行 一致性读 操作有了保证。换言之,就是为了查询一些正在被另-个事务更新的行,并且可以看到它们被更新之前的值,这样 在做查询的时候就不用等待另一个事务释放锁。在数据库中,对数据的操作主要有2种,分别是读和写,而在并发场景下,就可能出现以下三种情况:

读-读并发

读-写并发

写-写并发

我们都知道,在没有写的情况下发读-读并是不会出现问题的,而写-写并发这种情况比较常用的就是通过加锁的 方式实现。那么,读-写并发则可以通过MVCC的机制解决。

# 总结

MVCC(Multi-Version Concurrency Control,多版本并发控制)是MySQL中用于实现事务隔离级别的关键技术之一,特别是在InnoDB存储引擎中。MVCC允许数据库的读操作和写操作之间不相互阻塞,从而提高并发性能。

简单说就是,它是一种技术,用来解决——读和写并发情况中各种问题,和提高性能的。

# 快照读和当前读

MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理 读-写冲突,做到 即使有读写冲突时,也能做到 不加锁,非阻塞并发读 ,而这个读指的就是快照读,而非 当前读。 当前 读实际上是一种加锁的操作,是悲观锁的实现。

而MVCC本质是采用乐观锁思想的一种方式。

# 快照读

快照读又叫一致性读,读取的是快照数据。不加锁的简单的 SELECT 都属于快照读(这里有一个前提,mysql隔离级别处于RR-可重复读),即不加锁的非阻塞 读;比如,读取的是快照数据。这样:

SELECT * FROM xx_table WHERE
1

之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于MVCC,它在很多情况下,避免了加锁操作,降低了开销。 既然是基于多版本,那么快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。 快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。

# 当前读

和快照读相对应的另外一个概念叫做当前读,当前读,读取的是记录的最新版本(最新数据,而不是历史版本的数据),读取时还要保证其他并发事务 不能修改当前记录,会对读取的记录进行加锁。加锁的 SELECT,或者对数据进行增删改都会进行当前读。比如:

select * from xxx_table lock in share mode; # 共享锁
select * from xx_table for update; # 排他锁
insert into xx_table values(....)  # 排他锁
delete from xx_table ....   # 排他锁
update xx_table set xxx = xxx where ....# 排他锁
1
2
3
4
5

在 MySQL 的可重复读(Repeatable Read)隔离级别下,当前读使用的锁是 Next-Key Lock(临键锁)。这种锁是 InnoDB 引擎解决幻读问题的核心机制.

在 读已提交(Read Committed) 隔离级别下,当前读 使用的锁类型主要为 行级排他锁(X锁) 或 行级共享锁(S锁),具体取决于操作类型。

# 对比总结

特性 快照读 当前读
触发语句 普通SELECT SELECT ... FOR UPDATE、UPDATE等
数据版本 事务开始时的快照 最新提交的数据
加锁 无锁 加行锁(X锁/S锁)
阻塞写操作 否 是
适用场景 一致性查询(如报表) 需要原子更新的操作(如库存扣减)
隔离级别支持 所有隔离级别(行为不同) 所有隔离级别

# 解决的问题

  • 快照读:通过MVCC提供非阻塞的一致性视图,解决脏读、不可重复读,提升并发性能。
  • 当前读:通过加锁确保操作的原子性和隔离性,解决丢失更新和幻读。

# 实际应用场景

  • 快照读:适用于只读事务或需要历史数据一致性的场景(如生成报表)。
  • 当前读:适用于需要基于最新数据修改的场景(如支付扣款、库存扣减)。

# MVCC实现机制

# 实现原理

  • MVCC机制:通过事务版本号和Undo Log维护数据的多个版本。
    • 每个事务启动时会被分配一个唯一的事务ID(Transaction ID)。
    • 数据行中隐藏字段DB_TRX_ID记录修改该行的事务ID,DB_ROLL_PTR指向Undo Log中旧版本数据。
  • 可见性规则:事务只能看到:
    1. 事务ID小于当前事务ID的已提交修改。
    2. 自身事务的修改。

# MVCC到底解决了幻读没有

先说答案,没有解决

可重复的情况下,锁的只是当前版本的数据,也就是说是快照读,如果此时使用当前读,就可能出现幻读。

比如,A,B2个事务,B新增了一条数据,A 使用update 更新了新增的数据,之后在查询,就会发现多了一条数据。

原因核心:就是update语句用的不是快照读,for update也是一样

# 但MVCC+间隙锁解决了

间隙锁(Gap Lock)是InnoDB中的一种锁机制,用于防止其他事务在某个范围内插入新数据,从而避免幻读。

MVCC处理的是快照读的情况,通过版本链和Read View保证事务的一致性视图,这时候不会出现幻读。但当前读(比如SELECT FOR UPDATE)需要间隙锁来防止其他事务插入数据,这时候间隙锁就起作用了。当执行当前读时,InnoDB会加间隙锁,阻塞其他事务的插入,从而避免幻读。

需要明确的是两者是互补的。MVCC本身不能完全解决幻读,尤其是在当前读的情况下,必须依赖间隙锁。而间隙锁属于锁机制,和MVCC的多版本控制不同。

上次更新: 2025/04/23, 16:23:16
数据库出现死锁如何排查解决
几种count的性能比较

← 数据库出现死锁如何排查解决 几种count的性能比较→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式