MVCC(Multi-Version Concurrency Control):多版本并发控制
InnoDB存储引擎对MVCC的实现
多版本并发控制 (Multi-Version Concurrency Control)
MVCC 是一种并发控制机制,用于在多个并发事务同时读写数据库时保持数据的一致性和隔离性。它是通过在每个数据行上维护多个版本的数据来实现的。当一个事务要对数据库中的数据进行修改时,MVCC 会为该事务创建一个数据快照,而不是直接修改实际的数据行。
- 读(SELECT)
当一个事务执行读操作时,它会使用快照读取。快照读取是基于事务开始时数据库中的状态创建的,因此事务不会读取其他事务尚未提交的修改。具体工作情况如下:
- 对于读取操作,事务会查找符合条件的数据行,并选择符合其事务开始时间的数据版本进行读取
- 如果某个数据行有多个版本,事务会选择不晚于其开始时间的最新版本,确保事务只读取在它开始之前已经存在的数据
- 事务读取的是快照数据,因此其他并发事务对数据行的修改不会影响当前事务的读取操作
- 写操作(INSERT、UPDATE、DELETE)
- 当一个事务执行写操作时,它会生成一个新的数据版本,并将修改后的数据写入数据库。具体工作情况如下:
- 新版本的数据会带有当前事务的版本号,以便其它事务能够正确读取相应版本的数据
- 原始版本的数据仍然存在,供其它事务使用快照读取,这保证了其它事务不受当前事务的写操作
- 事务提交和回滚
- 当一个事务提交时,它所做的修改将成为数据库的最新版本,并且对其它事务可见
- 当一个事务回滚时,它所做的修改将被撤销,对其它事务不可见
- 版本的回收
为了防止数据库中的版本无限增长,MVCC 会定期进行版本回收,回收机制会删除已经不再需要的旧版本数据,从而释放空间。
MVCC 通过创建数据的多个版本和使用快照读取来实现并发控制。读操作使用旧版本数据的快照,写操作创建新版本,并确保原始版本仍然可用。这样,不同的事务可以在一定程度上并发执行,而不会相互干扰,从而提高了数据库的并发性能和数据一致性。
一致性非锁定读和锁定读
一致性非锁定读(Consistent Nonlocking Reads)
- 加一个版本号或时间戳字段
- 更新数据的同时:版本号 + 1 或者 更新时间戳
- 查询时,将当前可见的版本号与对应记录的版本号进行比对,如果记录的版本小于可见版本,则表示该记录可见
在 InnoDB 存储引擎中,多版本控制 (multi versioning)open in new window 就是对非锁定读的实现。如果读取的行正在执行 DELETE 或 UPDATE 操作,这时读取操作不会去等待行上锁的释放。相反地,InnoDB 存储引擎会去读取行的一个快照数据,对于这种读取历史数据的方式,我们叫它快照读 (snapshot read)
在 Repeatable Read 和 Read Committed 两个隔离级别下,如果是执行普通的 select 语句(不包括 select ... lock in share mode ,select ... for update)则会使用 一致性非锁定读(MVCC)。并且在 Repeatable Read 下 MVCC 实现了可重复读和防止部分幻读
锁定读(Locking Reads)
- select ... lock in share mode
- select ... for update
- insert、update、delete 操作
在锁定读下,读取的是数据的最新版本,这种读也被称为 当前读(current read)。锁定读会对读取到的记录加锁:
- select ... lock in share mode:对记录加 S 锁,其它事务也可以加S锁,如果加 x 锁则会被阻塞
- select ... for update、insert、update、delete:对记录加 X 锁,且其它事务不能加任何锁
在一致性非锁定读下,即使读取的记录已被其它事务加上 X 锁,这时记录也是可以被读取的,即读取的快照数据。上面说了,在 Repeatable Read 下 MVCC 防止了部分幻读,这边的 “部分” 是指在 一致性非锁定读 情况下,只能读取到第一次查询之前所插入的数据(根据 Read View 判断数据可见性,Read View 在第一次查询时生成)。但是!如果是 当前读 ,每次读取的都是最新数据,这时如果两次查询中间有其它事务插入数据,就会产生幻读。所以, InnoDB 在实现Repeatable Read 时,如果执行的是当前读,则会对读取的记录使用 Next-key Lock ,来防止其它事务在间隙间插入数据
InnoDB 对 MVCC 的实现
MVCC 的实现依赖于:隐藏字段、Read View、undo log
在内部实现中,InnoDB 通过数据行的 DB_TRX_ID 和 Read View 来判断数据的可见性,如不可见,则通过数据行的 DB_ROLL_PTR 找到 undo log 中的历史版本。每个事务读到的数据版本可能是不一样的,在同一个事务中,用户只能看到该事务创建 Read View 之前已经提交的修改和该事务本身做的修改
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix