InnoDB对MVCC的实现

MVCC是啥? (Multiversion Concurrency Control) 多版本并发控制

是个方法,是个思想。 解决多并发事务操作同一数据库数据,数据保持一致的问题。

怎么做:每个数据行上维护多个版本

当一个事务要对数据进行修改,为该事务创建一个数据快照,而不直接修改实际数据行。

读操作:有多个版本的数据,读最接近,早于事务开始时间的版本

写操作:不动原来的数据。事务重新创建一个副本操作,回滚了就无事发生,提交了就生成新一版数据。事务操作期间t0-t1的读,都读t0的版本。

为防止版本无限增长,定期进行回收,把不需要的旧版本数据删了,释放空间。

如果要读的行正在执行 DELETE 或 UPDATE 操作,读操作不等DELETE 或 UPDATE 操作完成。而是读最近的历史版本 ,这种读法叫快照读 (snapshot read)。


好 有了方法 要实现MVCC,InnoDB具体是怎么做的

为了实现MVCC,InnoDB 准备了三个东西:隐藏字段、Read View、undo log。

InnoDB 存储引擎为每行数据添加三个隐藏字段:

  • DB_TRX_ID:表示最后一次插入或更新该行的事务 id。delete 被视为更新,会在记录头 Record header 中的 deleted_flag 字段将其标记为已删除。

  • DB_ROLL_PTR: 回滚指针,指向该行的 undo log 。该行未被更新,则为空

  • DB_ROW_ID:如果没有设置主键且该表没有唯一非空索引,InnoDB 会使用该 id 来生成聚簇索引

会生成一个东西叫快照,即Read View,记录正在运行得事务的ID

这么多版本的数据放在哪里,放在undo log。

一个事务来了,要读a,InnoDB找到a,看Read View属性和DB_TRX_ID,判断是否可见,可见,直接读走。不可见,InnoDB通过DB_ROLL_PTR找到undo log中的最近历史版本读。

开始时间不同,每个事务读到的数据版本可能不同,同一个事务中,用户只能看到该事务开始时读的值和事务本身做的修改。

在 InnoDB 存储引擎中 undo log 分为两种:insert undo log 和 update undo log

insert undo log :指在 insert 操作中产生的 undo log。insert 操作的记录只对事务本身可见,对其他事务不可见,该 undo log 可以在事务提交后直接删除。不需要进行 purge 操作

update undo log :update 或 delete 操作中产生的 undo log。该 undo log可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge线程 进行最后的删除

不同事务或者相同事务对同一记录行的修改,会使该记录行的 undo log 成为一条链表,链首就是最新记录,链尾是最早的旧记录。

InnoDB 中,创建一个新事务后,执行每个 select 语句前,都会创建一个快照(Read View),**快照保存当前数据库中正活跃(没有 commit)的事务的 ID 号,**即保存的是系统中当前不应该被本事务看到的其他事务 ID 列表(即 m_ids)。

当用户在这个事务中要读取某个行时,InnoDB 会将该记录行的 DB_TRX_ID 与 Read View 中的一些变量及当前事务 ID 进行比较,判断是否满足可见性条件。


InnoDB 使用 MVCC生成 Read View 的时机不同:

  • RC : 每次select 前都生成一个Read View (m_ids 列表) 只要提交了都能读
  • RR :只在事务开始后 第一次select 前生成一个Read View(m_ids 列表)同一事务中要读到一样的数据

MVCC+Next-key-lock防止幻读

InnoDB存储引擎在 RR 级别下通过 MVCC和 Next-key Lock 来解决幻读问题:

1.执行普通 select,以 MVCC 快照读读数据

只在事务开启后第一次查询生成 Read View ,一直使用到事务提交。生成 Read View 之后其它事务的更新、插入记录版本对当前事务不可见,实现可重复读和防止快照读下的 "幻读"。

2.执行 select...for update/lock in share mode、insert、update、delete 等当前读

在当前读下,读的都是最新数据,如果其它事务有插入新记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB 使用 Next-key Lock解决。执行当前读时,锁定读到的记录和它们的间隙,防止其它事务在查询范围内插入数据。没有新增,就没有幻读。

相关推荐
Joy T1 小时前
Agent 确定性上下文设计:从 Prompt 参数注入到能力分层
java·开发语言·微服务·架构·prompt·agent context
AIgorithmGEEK4 小时前
MySQL 索引全解(下):建、查、删实战与知识速查表
数据库·mysql·b+树·索引
m0_587383004 小时前
广州 24 小时自助健身房解决方案技术实现与实战指南
java·spring·小程序·架构·需求分析
·云扬·4 小时前
Prompt 工程与安全:从 System 设计到注入防御
java·人工智能·安全·ai·prompt
专注仿真4 小时前
引擎扩展性与集成设计深度剖析:从 14 个扩展点到 DIS→HLA 演进之路
开发语言·算法·仿真引擎·推演引擎
Best-Wishes4 小时前
科来网络分析系统(技术交流版)使用说明书
开发语言·junit·php
代码不停5 小时前
自动化测试(java)
java·开发语言·selenium·自动化
唠点键盘之外的6 小时前
26 向量数据库实战:从 0 搭一条能用的检索链路(pgvector + Spring AI)
数据库·人工智能·spring
云和恩墨6 小时前
数据库监控简史:监控不止于告警——从图表大爆发到健康管理闭环
数据库
ly76896 小时前
MongoDB 事务开销实测:快照隔离下的写冲突、重试与分片事务边界
数据库·mongodb·事务·分片集群·快照隔离·写冲突