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解决。执行当前读时,锁定读到的记录和它们的间隙,防止其它事务在查询范围内插入数据。没有新增,就没有幻读。

相关推荐
芊寻(嵌入式)14 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
WaaTong16 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484416 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries18 分钟前
Java字节码增强库ByteBuddy
java·后端
一颗松鼠23 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
有梦想的咸鱼_25 分钟前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法
海阔天空_201330 分钟前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
MonkeyKing_sunyuhua36 分钟前
ubuntu22.04 docker-compose安装postgresql数据库
数据库·docker·postgresql
天郁青36 分钟前
数据库交互的本地项目:后台管理系统
数据库·交互
天下皆白_唯我独黑38 分钟前
php 使用qrcode制作二维码图片
开发语言·php