InnoDB对MVCC的实现

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

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

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

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

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

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

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

如果要读的行正在执行 DELETEUPDATE 操作,读操作不等DELETEUPDATE 操作完成。而是读最近的历史版本 ,这种读法叫快照读 (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 logupdate undo log

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

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

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

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

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


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

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

MVCC+Next-key-lock防止幻读

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

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

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

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

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

相关推荐
Arbori_262155 分钟前
获取oracle表大小
数据库·oracle
王强你强12 分钟前
MySQL 高级查询:JOIN、子查询、窗口函数
数据库·mysql
草巾冒小子13 分钟前
brew 安装mysql,启动,停止,重启
数据库·mysql
用户62799471826219 分钟前
南大通用GBase 8c分布式版本gha_ctl 命令-HI参数详解
数据库
The Future is mine26 分钟前
Python计算经纬度两点之间距离
开发语言·python
Enti7c27 分钟前
HTML5和CSS3的一些特性
开发语言·css3
斯汤雷28 分钟前
Matlab绘图案例,设置图片大小,坐标轴比例为黄金比
数据库·人工智能·算法·matlab·信息可视化
腥臭腐朽的日子熠熠生辉32 分钟前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
爱吃巧克力的程序媛34 分钟前
在 Qt 创建项目时,Qt Quick Application (Compat) 和 Qt Quick Application
开发语言·qt
ejinxian34 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring