Mysql如何实现原子性(MVCC实现原理)
Mysql实现原子性主要通过一下机制
- 锁
- MVCC多版本并发控制
MVCC的实现原理
在介绍MVCC的实现原理之前需要先介绍一下Mysql表中的隐藏字段 , 以及undo_log版本链以及readview
1. Mysql中的隐藏字段
Mysql在创建表的时候除了我们所定义的字段还定义了一下三个字段
- DB_TEX_ID --> 同来记录当前事务ID , 该字段是一个自增的Int , 每当事务开启后 , 就会对该ID自增
- DB_ROLL_TRX --> 该字段是记录上一个undo_log日志的地址
- DB_ROW_ID --> 当用户未指定主键时 , 该字段会作为主键
2. 什么是undo_log版本链
在事务执行增删改之前 , 会在undo_log日志当中记录当前的数据信息 , 并保存DB_TROLL_TAX记录上一个undo_log日志地址
如下图所示 , 我们开启了四个事务 , 对于每个事务的版本号为2 , 3 , 4 ,5
那么在事务的创建过程中就会在undo_log日志当中注册版本信息 , 如下图
那么当上述的事务都注册完毕就会形成一个版本链
3. 什么是readview
readview就是通过一定的机制来判断 , 当前版本的事务是否可以被读取 , 也就是说是快照读 sql执行的依据
当前读:
当前读就是记录最新版本的数据 , 在读取过程中会加锁
快照读
就是简单的select语句 , 在读取过程中不加锁 是非阻塞的 , 读取的数据有可能是当前数据 ,也有可能是历史数据
而对于快照读所读取的数据是什么也就是通过readview一下几点来实现的
首先在readview中保存了下列字段 , 分别用来记录当前并发日志的信息 , 通过该消息与一定的规则来实现快照读
规则如下
4. MVCC是如何基于readview, undo_log版本链与隐藏字段实现快照读
还是针对下述事务 , 我们来判断一下事务无的;i两次快照读分别命中了那个版本的数据
首先我们来分析第一次查询
m_ids: { 3 , 4 , 5}
min_trx_id: 3
max_trx_id : 6
creator_trx_id : 5
分析完readview后我们就要从undo_log版本链进行比对
可以看出来对于第一个查询命中的事务2 , 对于第二个查询命中的是事务3
介绍完隐藏字段 , undo_log日志链与readview这三个概念后, 对于MVCC要做什么怎么做应该有了一个大致的了解
MVCC多版本并发控制也就是在多个事务并发的情况下 , 通过readview判断快照读命中的是哪个语句 , 进而获取查询信息
简述一下你对MVCC机制的理解?
mvcc机制翻译过来也就是多版本并发控制,MySQL采取该机制主要是为了解决并发情况下事务的三种场景,读读(在并发环境中对读读不会产生影响),读写(脏读,幻读,不可重复读),写写(脏写)。mvcc机制通过非阻塞读的方式来提高并发情况下的读写性能,同时也通过readview机制与undolog版本链实现快照读的版本选择。对于不同的事物隔离级别快照读的时机,对于读已提交情况在每次读取都会生成一个快照,而对于可重复读只会在第一次读的时候生成快照从而保证多次读取数据的一致性
同时对于readview,该机制是帮助快照读选取具体的版本的。在readview中保存了四个字段分别为活跃事物id,最小事物id,最大事物id,当前执行事务id。除此之外还提供了一定的规则来判断具体哪个undolog事务版本可以被采用,主要为一下几点。
- 如果该事务执行完毕,则运行访问,具体表现为事务版本小于最小ID;或者事务id在最大id和最小id之前且为非活跃id2. 如果是当前事务读,则运行访问,具体表现为,事务id等于当前事务ID3. 如果事务在快照读之后开启,则不允许访问,具体表现为事务id大于最大id
undolog版本链,也就是对于所有事物在执行前需要现在undolog日志当中记录所执行数据的当前状态与上一个版本的指针地址,当多个事务完成注册就可以通过上版本的指针地址链接形成一个版本链
=============================================================
面试官:事务中的隔离性是如何保证的呢?(你解释一下MVCC)
候选人:事务的隔离性是由锁和mvcc实现的。
其中mvcc的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为了三个部分,第一个是隐藏字段,第二个是undo log日志,第三个是readView读视图
隐藏字段是指:在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事务id),记录每一次操作的事务id,是自增的;另一个字段是roll_pointer(回滚指针),指向上一个版本的事务版本记录地址
undo log主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表
readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生成ReadView,后续复用