什么是MVCC,一文搞懂MySQL的MVCC机制
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_id、roll_ptr,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列row_id。
MySQL行记录中除了记录业务数据外,还有隐藏的 trx_id 和 roll_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的事务
流程说明:
- 获取事务自己的版本号,即事务ID
- 获取Read View
- 查询得到的数据,然后Read View中的事务版本号进行比较。
- 如果不符合Read View的可见性规则, 即就需要Undo log中历史快照;
- 最后返回符合规则的数据
演示说明:
提交了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机制相关推荐
- 一文搞懂MySQL数据库分库分表
如果数据量过大,大家一般会分库分表.分库需要注意的内容比较少,但分表需要注意的内容就多了. 工作这几年没遇过数据量特别大的业务,那些过亿的数据,因为索引设置合理,单表性能没有影响,所以实战中一直没用过 ...
- 一文搞懂 MySQL 索引
一文搞懂 MySQL 索引 1.MySQL 索引 简介 1.1.MySQL 索引 是什么? 索引是一个单独的.存储在 磁盘 上的 数据库结构 ,包含着对数据表里 所有记录的 引用指针. 1.2. M ...
- 一文搞懂MySQL XA如何实现分布式事务
一文搞懂MySQL XA如何实现分布式事务 前言 XA 协议 如何通过MySQL XA实现分布式事务 前言 MySQL支持单机事务的良好表现毋庸置疑,那么在分布式系统中,涉及多个节点,MySQL又是如 ...
- 一文搞懂 Python 的 import 机制
一.前言 希望能够让读者一文搞懂 Python 的 import 机制 1.什么是 import 机制? 通常来讲,在一段 Python 代码中去执行引用另一个模块中的代码,就需要使用 Python ...
- 一文搞懂MySQL体系架构!!
写在前面 很多小伙伴工作很长时间了,对于MySQL的掌握程度却仅仅停留在表面的CRUD,对于MySQL深层次的原理和技术知识了解的少之又少,随着工作年限的不断增长,职场竞争力却是不断降低的.很多时候, ...
- 一文搞懂MySQL的Join
点击上方 "程序员小乐" ,关注公众号 8点20分,第一时间与你相约 每日英文 A single hand that wipes tears during failures is ...
- ❤『知识集锦』一文搞懂mysql索引!!(建议收藏)
作者:不吃西红柿 简介:CSDN博客专家.蓝桥签约作者.大数据领域优质创作者. 以我的资历和文凭,将来这个城市的大街,都归我扫. [系列课程介绍] 『面试知识集锦』系列课程包括以下20个系列,超过 ...
- JAVA秒杀mysql层实现_一文搞懂MySQL的Join,聊一聊秒杀架构设计
正文 MySQL的Join到底能不能用 经常听到2种观点: join性能低,尽量少用 多表join时,变为多个SQL进行多次查询 其实对于上面的观点一定程度上是正确的,但不是完全正确.但之所以流传这么 ...
- 一文搞懂mysql:mysql学习目录链接大全
之前学习了mysql.整理出来分享给大家. 序号 名字 1 mysql数据库入门教程(1):数据库的相关概念,存储特点,软件安装教程,数据库启动,服务端登录退出 2 mysql数据库入门教程(2):常 ...
最新文章
- Java 二进制,八进制,十进制,十六进制
- 计算机合成生物学博士,重磅!Tim Lu 出任 CEO,合成生物学新锐今日闪亮登场
- 测验1: Python基本语法元素 (第1周)
- 百练OJ:2810:完美立方
- Gdiplus::GdiplusBase::operator new 函数不接受3 个参数问题的处理
- temp变量this变量base变量 c# 1613715552
- 远程服务器存储之JSON
- linux vnc离线安装包,Linux之部署vnc应用
- Python类调用实例方法
- layui自定义表单验证无效
- ftl有三种映射地址_ftl 入门
- 2020浙江大学软件学院软件工程考研经验分享
- hdu 1290 (切西瓜问题)
- 登录页面,登录后跳转不成功
- 陀螺产业区块链第十五季 | 博雅正链RegChain
- 如何借助「星图地球开发者平台」实现智慧环保可视化?
- 查看tmp目录下的文件
- OllyDbg断点详解
- Python——format
- 云安全问题及其解决方案