MVCC是什么

MVCC,即Multi-Version Concurrency Control (多版本并发控制)。它是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

数据库中同时存在多个版本的数据,并不是整个数据库的多个版本,而是某一条记录的多个版本同时存在,在某个事务对其进行操作的时候,需要查看这一条记录的隐藏列事务版本id,比对事务id并根据事物隔离级别去判断读取哪个版本的数据。

数据库隔离级别读已提交、可重复读 都是基于MVCC实现的,相对于加锁简单粗暴的方式,它用更好的方式去处理读写冲突,能有效提高数据库并发性能。

我们先回顾一下事务的相关概念,以便更好的理解mvcc的实现原理

MySQL的事务

redo log

redo log重做日志,是记录物理数据变化的日志,使用数据库DML对数据的修改操作,都会产生redo log,可以保证事务的持久性

undo log

undo log是回滚日志,有两个作用:提供回滚操作多行版本控制(MVCC)

在数据修改的时候,不仅记录了redo,还记录了相对应的undo,如果因为某些原因导致事务失败或回滚了,可以借助undo进行回滚,

undo log和redo log记录物理日志不一样,undo log主要记录的是数据的逻辑变化,它是逻辑日志

可以认为执行insert时会对应在undo log中记录一条delete语句,并且会记录这个版本的事务id(txid),执行update语句会有一条update语句来使之数据恢复到上个版本。

当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚

多行版本控制的时候,也是通过undo log来实现的

当读取的某一行被其它事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么。从而提供该行版本信息。

并且undo log的内容变更也会记录到redo log中,从而实现undo log的持久化

总而言之就是undo log提供了一种数据库快照的功能,通过事务id和undo log我们可以找到历史版本的数据

MySQL事务的隔离级别

SQL标准中定义了四个隔离级别:

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能导致脏读、幻读、不可重复读;
  • READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读任有可能发生
  • REPAATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据本身是被本身事务所修改的,可以阻止脏读和不可重复读,但幻读仍有可能发生
  • SETIALIZABLE(可串行化):最高的隔离级别,完全服从ACID原则,所有事务单个依次执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读,不可重复读以及幻读。

MVCC原理

事务版本号

事务每次开启前,都会从数据库获取一个自增长的事务ID,可以从事务ID判断事务的执行先后顺序

隐式字段

对于InnoDB存储引擎,每一行记录都有两个隐藏列trx_idroll_ptr,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列row_id

MySQL行记录中除了记录业务数据外,还有隐藏的 trx_idroll_ptr

  • trx_id:表示最近修改的事务的id,每次一个事务对某条聚集索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列,新增一个事务时,trx_id就会递增,因此trx_id能够表示事务开始的先后顺序
  • roll_ptr:指向上一个版本的地址,每次对某条聚集索引记录进行改动时,都会把旧版本写入undo log中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

版本链

MySQL的每行记录逻辑上其实是一个链表

演示说明:


update user set name = '肉蟹宝1' where id = 1 

这个链表存在于undo log中,和最新版本的数据不在一起

每次更新后,都会将旧值放在一条undo log中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_ptr属性连接成一个链表,我们把这个链表称为版本链,版本链的头节点就是当前记录最新的值

另外,每个版本中还包含生成该版本时对应的事务id(trx_id)

ReadView

说完了undo log 和版本链,再来说说ReadView,前面我们说过MVCC只在read_commited和repeatable_read两个隔离级别下工作,而read_commited和repeatable_read的区别不同就在于它们生成的ReadView的策略不同

对于使用read_commited和repeatable_read隔离级别的事务来说,都必须保证读到已经提交了的事务修改过的记录,也就是说假如另一个事务已经修改了记录但未提交,是不能直接读取最新版本的记录的

核心问题就是:需要判断一下,版本链中哪个版本是当前事务可见的

为此InnoDB提出了一个ReadView的概念,这个ReadView中有一个id列表,trx_ids来存储系统中当前活跃着的读写事务,也就是begin了但是还未commit或rollback的事务

流程说明:

  1. 获取事务自己的版本号,即事务ID
  2. 获取Read View
  3. 查询得到的数据,然后Read View中的事务版本号进行比较。
  4. 如果不符合Read View的可见性规则, 即就需要Undo log中历史快照;
  5. 最后返回符合规则的数据

演示说明:

提交了trx_id是2的记录后,接着新建trx_id为3的事务,修改name的值,但是事务还没有提交

update user set name = '肉蟹宝 2 ' where id = 1 

则此时的版本链是:

显然,此时的trx_ids为[3]

如果另一个事务查询id为1的记录,因为trx_ids当前只有trx_id为3的事务,而trx_ids的意义是记录未完成的事务。在这里,事务未完成,所以该条记录不可见,继续查询下一条,结果返回肉蟹宝1

此时我把trx_id为3的事务提交了,并且新建了一个trx_id为4的事务,修改name,且不提交事务

update user set name = '肉蟹宝 3 ' where id = 1 

这时的版本链就是:

read-committed —— 每次查询数据前都生成一个 ReadView

trx_ids 将更新为[ 4 ],版本链通过 trx_id 对比查找到的结果就是肉蟹宝2

repeatable-read —— 在第一次查询数据时生成一个 ReadView,之后的读都复用之前的。

不会有重建的 ReadView , trx_ids 还是 [ 3 ],MySQL 认为事务3未完成,所以 select 的结果是肉蟹宝1。第2次 select 结果和第1次一样,所以叫可重复读。

小结

从上边的描述中我们可以看出来,所谓的MVCC--多版本并发控制指的就是在使用read-commited、repeatable-read这两种隔离级别的事务在执行select操作时,访问记录的版本链的过程。这样子就可以使不同的事务的读-写、写-读作并发执行,从而提升系统性能。

read-commited、repeatable-read这两个隔离级别的很大一个不同就是:生成ReadView的时机不同

read-commited 在每一次进行select操作时都会生成一个ReadView,而repeatable-read只在第一次进行普通select操作时生成一个ReadView,之后的查询操作都重复使用这个ReadView

参考与感谢:

深入理解MYSQL的MVCC机制

javaguide

什么是MVCC,一文搞懂MySQL的MVCC机制相关推荐

  1. 一文搞懂MySQL数据库分库分表

    如果数据量过大,大家一般会分库分表.分库需要注意的内容比较少,但分表需要注意的内容就多了. 工作这几年没遇过数据量特别大的业务,那些过亿的数据,因为索引设置合理,单表性能没有影响,所以实战中一直没用过 ...

  2. 一文搞懂 MySQL 索引

    一文搞懂 MySQL 索引 1.MySQL 索引 简介 1.1.MySQL 索引 是什么?  索引是一个单独的.存储在 磁盘 上的 数据库结构 ,包含着对数据表里 所有记录的 引用指针. 1.2. M ...

  3. 一文搞懂MySQL XA如何实现分布式事务

    一文搞懂MySQL XA如何实现分布式事务 前言 XA 协议 如何通过MySQL XA实现分布式事务 前言 MySQL支持单机事务的良好表现毋庸置疑,那么在分布式系统中,涉及多个节点,MySQL又是如 ...

  4. 一文搞懂 Python 的 import 机制

    一.前言 希望能够让读者一文搞懂 Python 的 import 机制 1.什么是 import 机制? 通常来讲,在一段 Python 代码中去执行引用另一个模块中的代码,就需要使用 Python ...

  5. 一文搞懂MySQL体系架构!!

    写在前面 很多小伙伴工作很长时间了,对于MySQL的掌握程度却仅仅停留在表面的CRUD,对于MySQL深层次的原理和技术知识了解的少之又少,随着工作年限的不断增长,职场竞争力却是不断降低的.很多时候, ...

  6. 一文搞懂MySQL的Join

    点击上方 "程序员小乐" ,关注公众号 8点20分,第一时间与你相约 每日英文 A single hand that wipes tears during failures is ...

  7. ❤『知识集锦』一文搞懂mysql索引!!(建议收藏)

    作者:不吃西红柿 简介:CSDN博客专家.蓝桥签约作者.大数据领域优质创作者. 以我的资历和文凭,将来这个城市的大街,都归我扫.   [系列课程介绍] 『面试知识集锦』系列课程包括以下20个系列,超过 ...

  8. JAVA秒杀mysql层实现_一文搞懂MySQL的Join,聊一聊秒杀架构设计

    正文 MySQL的Join到底能不能用 经常听到2种观点: join性能低,尽量少用 多表join时,变为多个SQL进行多次查询 其实对于上面的观点一定程度上是正确的,但不是完全正确.但之所以流传这么 ...

  9. 一文搞懂mysql:mysql学习目录链接大全

    之前学习了mysql.整理出来分享给大家. 序号 名字 1 mysql数据库入门教程(1):数据库的相关概念,存储特点,软件安装教程,数据库启动,服务端登录退出 2 mysql数据库入门教程(2):常 ...

最新文章

  1. Java 二进制,八进制,十进制,十六进制
  2. 计算机合成生物学博士,重磅!Tim Lu 出任 CEO,合成生物学新锐今日闪亮登场
  3. 测验1: Python基本语法元素 (第1周)
  4. 百练OJ:2810:完美立方
  5. Gdiplus::GdiplusBase::operator new 函数不接受3 个参数问题的处理
  6. temp变量this变量base变量 c# 1613715552
  7. 远程服务器存储之JSON
  8. linux vnc离线安装包,Linux之部署vnc应用
  9. Python类调用实例方法
  10. layui自定义表单验证无效
  11. ftl有三种映射地址_ftl 入门
  12. 2020浙江大学软件学院软件工程考研经验分享
  13. hdu 1290 (切西瓜问题)
  14. 登录页面,登录后跳转不成功
  15. 陀螺产业区块链第十五季 | 博雅正链RegChain
  16. 如何借助「星图地球开发者平台」实现智慧环保可视化?
  17. 查看tmp目录下的文件
  18. OllyDbg断点详解
  19. Python——format
  20. 云安全问题及其解决方案

热门文章

  1. 无人机航测-倾斜摄影在房地一体权籍的应用
  2. 用原版XP SP3集成最新补丁制作ISO镜像的方法
  3. Shell 写入csv处理中文乱码
  4. 联想 Linux下 装win10 双系统(免坑)
  5. 双骰子游戏——简单语句实现,do while循环
  6. coco数据集的学习和理解
  7. 自学Scala的第四天——去leetcode上刷刷题,顺便学学基础语法
  8. 思维导图怎么画:多方法绘制自己喜欢的思维导图技巧
  9. 用计算机怎么扣税点,工资超过3500怎么扣税 利用计算器轻松算缴纳金额
  10. windows命令行下查看进程号