MySQL如何实现原子性(MVCC实现原理)
MySQL如何实现原子性(MVCC实现原理)
MySQL如何实现原子性(MVCC实现原理)
MySQL实现原子性主要通过以下机制:
- 锁
- MVCC多版本并发控制
MVCC的实现原理
在介绍MVCC的实现原理之前,需要先介绍一下MySQL表中的隐藏字段,以及undo_log版本链和readview。
1. MySQL中的隐藏字段
MySQL在创建表的时候除了用户定义的字段外,还会定义以下三个隐藏字段:
DB_TRX_ID
:用来记录当前事务ID,该字段是一个自增的Int,每当事务开启后,就会对这个ID自增。DB_ROLL_PTR
:该字段记录上一个undo_log日志的地址。DB_ROW_ID
:当用户未指定主键时,该字段会作为主键。
2. 什么是undo_log版本链
在事务执行增删改之前,会在undo_log日志中记录当前的数据信息,并保存DB_ROLL_PTR记录上一个undo_log日志地址。如下图所示,我们开启了四个事务,对于每个事务的版本号为2、3、4、5:
那么当上述的事务都注册完毕就会形成一个版本链:
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之间且为非活跃ID
- 如果是当前事务读,则运行访问,具体表现为,事务ID等于当前事务ID
- 如果事务在快照读之后开启,则不允许访问,具体表现为事务ID大于最大ID
undolog版本链,也就是对于所有事务在执行前需要现在undolog日志当中记录所执行数据的当前状态与上一个版本的指针地址,当多个事务完成注册就可以通过上版本的指针地址链接形成一个版本链。