MySQL面试系列:MVCC是怎么实现的?(三)
前言
上篇文章SQL查询语句是如何执行的提到了日志文件:binlog、redo log 、undo log,那接下来我们接着详细聊聊undo log和MVCC是怎么实现的。
一、事务隔离级别
先了解一个概念:隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
- 读未提交:能够随意读取其他事务未提交的数据和已提交的数据。形象解释:所有的数据在一个屋子里面,任何事务修改对于其他事务都是可见的。
- 读已提交:不能读取其他事务未提交的数据,但是能读到其他事务已提交的数据。形象解释:一个屋子里有了一个小隔间,事务没提交的时候数据都在小隔间,一但事务提交了,就把数据放到大厅中,其他事务都可见了。
- 可重复读(默认设置):其他事务提交了数据也不可见,每次查询结果都是一致的。形象解释:每个事务都在自己的小隔间操作,其他事务提交了数据,放到了大厅,自己也是不知道的。
- 串行化:所有事务串行执行。
你是否也想问这样一个:MySQL的事务隔离级别是怎么实现的呢?这就是我们接下来要聊的重要话题。
什么是幻读
当同一查询在不同时间产生不同的行集时,在事务内就会发生 所谓的幻象问题。例如,如果事务A SELECT执行两次,但是第二次返回的行却不是第一次返回,则该行是“ phantom ”行。
怎么解决
To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking. (官方文档)
翻译:next-key lock 即行锁和间隙锁解决了幻读问题,(index-row lock with gap lock = next-key lock)
二、Undo log
Undo log是InnoDB MVCC事务特性的重要组成部分,也是数据回滚依赖的对象。
主备工作
新建一个表:
mysql> create table user(id int primary key, name varchar, age int);
插入一行数据:
mysql> insert into user values("1","张三",30);
在数据库中实际存储的时候它还会有3个隐藏的字段:DB_TRX_ID(事务ID ) 、DB_ROLL_PTR(回滚指针)、DB_ROW_ID(主键ID)
字段 | 作用 |
---|---|
DB_TRX_ID | 表示插入或更新该行的最后一个事务的事务标识符 |
DB_ROLL_PTR | 表示指向该行回滚段(rollback segment)的指针,InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在 undo 中都通过链表的形式组织。 |
DB_ROW_ID | 行标识(该行ID随着插入新行而单调增加),如果表没有主键且没有唯一索引,InnoDB 会自动生成一个隐藏主键。 【思考为什么要有这样一个字段】 |
每条记录的头信息(record header)里都有一个专门的bit(deleted_flag)来表示当前记录是否已经被删除,即delete数据的时候会用deleted_flag来标记该数据已删除。(不用深究,记住有这么一个字段就行)
如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引、如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引、如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引。
用一张图来看看插入一条数据之后的样子:
再有更新语句的时候,我们来看看undo log中的存储情况:
在每次修改聚集索引页上的记录时,变更之前的记录都会写到undo日志中。可以根据回滚段指针找到最近一次修改之前的undo记录,而每条Undo记录又能再次找到之前的变更。
回滚操作也比较简单,读取老版本记录,做逆向操作即可:
对于删除操作,清理标记删除标记;
对于更新操作,将数据回滚到最老版本;
对于插入操作,直接删除聚集索引和二级索引记录。
三、MVCC是什么?怎么实现的?
英文全称为Multi-Version Concurrency Control,翻译为中文即 多版本并发控制。
InnoDB有两个非常重要的模块来实现MVCC,一个是undo日志,用于记录数据的变化轨迹,用于数据回滚,另外一个是Read View,用于判断一个session对哪些数据可见,哪些不可见。
Read View:它用于控制数据的可见性
在InnoDB中,只有读查询才会去构建ReadView视图,对于类似DML这样的数据更改,无需判断可见性,而是单纯的发现事务锁冲突,直接堵塞操作。
ReadView包含几个重要的变量用于判断记录的可见范围:
ReadView::id 创建该视图的事务ID;
ReadView::m_ids 创建ReadView时,活跃的读写事务ID数组,有序存储;(“活跃”指的就是启动了,但还未提交)
ReadView::m_low_limit_id 设置为当前最大事务ID;
ReadView::m_up_limit_id m_ids集合中的最小值,如果m_ids集合为空,表示当前没有活跃读写事务,则设置为当前最大事务ID。
可见性判断逻辑:
- 如果记录的trx_id小于ReadView::m_up_limit_id,则说明该事务在创建ReadView时已经提交了,肯定可见;
- 如果记录的trx_id大于等于ReadView::m_low_limit_id,则说明该事务是创建readview之后开启的,肯定不可见;
- 当trx_id在m_up_limit_id和m_low_limit_id之间时,如果在ReadView::m_ids数组中,说明创建readview时该事务是活跃的,其做的变更对当前视图不可见,否则对该trx_id的变更可见。
通过上面的判断,该数据变更还是不可见时,就尝试通过undo去构建老版本记录,直到找到可见的记录,或者到达undo链表头都未找到。
如果我们查询得到的是一条二级索引记录逻辑还稍微有点区别,我觉得你能把上面的东西说出来就可以了,这点细节估计一面面试官自己都不知道,后面研究也不迟。
不同隔离级别下,可见性的判断有很大的不同
READ-UNCOMMITTED 在该隔离级别下会读到未提交事务所产生的数据更改,这意味着可以读到脏数据,因为它根本不会去检查可见性或是查看老版本。
READ-COMMITTED 在该隔离级别下,可以在SQL级别做到一致性读,当事务中的SQL执行完成时,ReadView被立刻释放了,在执行下一条SQL时再重建ReadView。这意味着如果两次查询之间有别的事务提交了,是可以读到不一致的数据的。
REPEATABLE-READ 可重复读和READ-COMMITTED的不同之处在于,当第一次创建ReadView后(例如事务内执行的第一条SEELCT语句),这个视图就会一直维持到事务结束。也就是说,在事务执行期间的可见性判断不会发生变化,从而实现了事务内的可重复读。
SERIALIZABLE 序列化的隔离是最高等级的隔离级别,当一个事务在对某个表做记录变更操作时,另外一个查询操作就会被该操作堵塞住。同样的,如果某个只读事务开启并查询了某些记录,那么另外一个session对这些记录的更改操作是被堵塞的。
看完这些我们就可以来说说InnoDB ACID了
- Atomicity (原子性)
所谓原子性,就是一个事务要么全部完成变更,要么全部失败。(undo log) - Consistency (一致性)
一致性指的是数据库需要总是保持一致的状态,即使实例崩溃了,也要能保证数据的一致性。 - Isolation (隔离性)
隔离性是指多个事务不可以对相同数据同时做修改,事务查看的数据要么就是修改之前的数据,要么就是修改之后的数据。(四种隔离级别) - Durability(持久性)
当一个事务完成了,它所做的变更应该持久化到磁盘上,永不丢失。(redo log)
启动事务时begin/start transaction,执行第一条SQL语句才会创建一个视图 ReadView
总结
Innodb使用一种称做ReadView(视图)的对象来判断事务的可见性(也就是ACID中的隔离性)。 Innodb在执行一个SELECT时会创建一个视图对象。
又通过undo log的版本链去查询可见数据。
对于RR隔离级别,视图的生命周期到事务提交结束,对于RC隔离级别,则每条查询开始时重分配事务。
在 REPEATABLE-READ隔离级别还能START TRANSACTION WITH CONSISTENT SNAPSHOT 显式开启(可忽略)
本章所有的知识点是必须掌握的,并且自己需要理一下怎么简短的回答面试的问题。
MySQL面试系列:MVCC是怎么实现的?(三)相关推荐
- 【MySQL 面试系列】索引原理
文章目录 一.索引概述 1.索引的定义 2.索引的作用 3.索引的优缺点 二.索引结构 1.概述 2.索引的演进 1.二叉树 2.B-Tree 3.B+Tree 4.Hash 二.索引分类 1.MyS ...
- 程序员面试系列,MySQL常见面试题?
原文链接 一.索引相关的面试题 (1)索引失效的情况有哪些 在MySQL查询时,以下情况可能会导致索引失效,无法使用索引进行高效的查询: 数据类型不匹配:如果查询条件中的数据类型与索引列的数据类型不匹 ...
- 数据库MYSQL学习系列三
数据库MYSQL学习系列三 三.MYSQL事务与存储引擎 3.1-数据库事务 什么是事务 一系列有序的数据库操作: o要么全部成功 o要么全部回退到操作前的状态 o中间状态对其他连接不可见 事务的 ...
- MySQL优化系列(二)--查找优化(1)(非索引设计)
MySQL优化系列(二)--查找优化(1)(非索引设计) 接下来这篇是查询优化,用户80%的操作基本都在查询,我们有什么理由不去优化他呢??所以这篇博客将会讲解大量的查询优化(索引以及库表结构优化等高 ...
- 面试系列一:精选大数据面试真题10道(混合型)-附答案详细解析
本公众号(五分钟学大数据)将推出大数据面试系列文章-五分钟小面试,此系列文章将会深入研究各大厂笔面试真题,并根据笔面试题扩展相关的知识点,助力大家都能够成功入职大厂! 大数据笔面试系列文章分为两种类型 ...
- mysql知识点系列-数据目录(Data目录)下文件类型一窥究竟
本文主要基于<高性能MySQL> 文章目录 1.数据库目录 2.frm文件 3.ibd文件 4.ibdata文件 5.ib_logfile文件 6.UNDO日志 7.慢查询日志 8.二进制 ...
- 手撸架构,Mysql 面试126问
技术栈 传送门 JAVA 基础 手撸架构,Java基础面试100问_vincent-CSDN博客 JAVA 集合 手撸架构,JAVA集合面试60问_vincent-CSDN博客 JVM 虚拟机 手撸架 ...
- 1.MySQL面试宝典
1.八股文带你吊打面试官之MySQL 我们很多小伙伴平时会看很多面试八股文,但是经常遇到一个问题,结论是知道了,但是面试官继续深剖,问我们底层实现,这时我们懵圈了,因此我专门出一期面试突击专题,帮助各 ...
- MYSQL面试总结(一)
目录 MYSQL面试总结 一.学习教程资源 二.介绍MYSQL 三.MYSQL存储引擎介绍 四.索引 一.学习教程资源 菜鸟教程:用于初学者初步了解mysql https://www.runoob.c ...
最新文章
- VMware 虚拟化编程(4) — VDDK 安装
- 今天又看到的Acm指南
- LeetCode—33. 搜索旋转排序数组
- ocp证书怎么考_没有基础怎么考初级会计证书?
- Codeforces Round #465 (Div. 2) F. Fafa and Array
- java爬虫登录_Java爬虫中怎么爬取需要登录的网站
- 电影海报的字体如何设计?——黎乙丙
- 关于影视后期制作的就业市场调查报告
- spyder5 更改为简体中文的方法,与spyder4不同
- 目标检测拉近镜头数据增强
- 线性代数------矩阵1
- 在线的h5编辑器汇总和分析
- PAT(甲级)渡劫(一)-Public Bike Management
- 手机端H5页面边框缺失问题解决
- 用AkShare获取沪深京A股所有股票历史数据
- 自动化改造要想取得最大效益,要搞清这几个问题!
- grub linux修复 pe,恢复Ubuntu GRUB引导的方法
- Linux中进程的状态
- 项目中关于图片上传与剪裁的流程
- CrackMe003:NAG窗口(4C法)和浮点计算