vlambda博客
学习文章列表

MYSQL的隔离机制实现

MYSQL的隔离机制实现
GENERAL TITLE
本文将详细剖析MYSQL的隔离机制实现相关的面试问题,下次面试官说"请谈谈MYSQL的隔离机制实现",请直接将面试官按到地摩擦。

快照读就是普通读,例如select * from table,不包含加读写锁的形式。

SELECT ... FOR UPDATE 
SELECT ... LOCK IN SHARE MODE

而当前读是读取最新版本。


快照读实现方式

聊快照读实现方式之前,先说说什么是MVCC。

何为MVCC,称为多版本并发控制,可以实现读的时候不加锁,也能实现不同隔离级别。


在聚簇索引行记录中,没条记录会额外保存几个字段row_id(用于没有主键,唯一索引时用作主键索引),trx_id(记录当前事务ID,每个事务开启时会向系统申请一个事务ID,按申请顺序严格递增)、roll_pointer(回滚指针,指向undolog中保存的旧数据)。


其实当记录发送修改时,会将原来的记录保存在undolog(回滚日志)中,然后回滚指针会指向该位置,由此会形成一条版本链,也就是说,一条记录可能会有多个版本。

MYSQL的隔离机制实现


接下来将介绍Read-view:

在MySQL里,有两个“视图”的概念:

一个是view。它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是create view ... ,而它的查询方法与表一样。

另一个是InnoDB在实现MVCC时用到的一致性读视图,即consistent read view,用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。

今天为了说明查询和更新的区别,我换一个方式来说明,把read view拆开分析:

我这里没有官方解释,简单来说就是当你开启事务时,会将当前活跃事务ID集(未提交的事务)存到一个数组,称为“视图数组”,以最小的活跃事务ID作为低水位,以系统最大事务ID+1作为高水位。

即Read View由三部分组成:

1、当前活跃的事务ID列表【101,102】

2、低水位,活跃事务的最小值Tmin=102

3、系统中最大事务ID加一Tmax=103

相当于把所有row_trx_id分成三部分,已提交事务,未提交事务,未开始事务,如图所示:

MYSQL的隔离机制实现

这样,对于当前事务的启动瞬间来说,一个数据版本的row trx_id,有以下几种可能:

  1. 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;

  2. 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;

  3. 如果落在黄色部分,那就包括两种情况
    a. 若 row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
    b. 若 row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。

一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以外,有三种情况:

版本未提交,不可见;

版本已提交,但是是在视图创建后提交的,不可见;

版本已提交,而且是在视图创建前提交的,可见。

然后,在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。这样以来,便实现了不同的隔离级别以及快照读。

另外,更新数据都是先读后写的,而这个读,只能读当前的值 (读最新的版本),称为“当前读”(current read)。

两阶段锁协议:行锁等事务结束才释放。

可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。

当前读实现方式

当前读,读取的是最新版本,并且需要先获取对应记录的锁,如以下这些 SQL 类型:

select ... lock in share mode 、

select ... for update、

update 、delete 、insert

当前读是通过 next-key 锁(行记录锁+间隙锁)来是实现的。

最后,想必弄懂以上所诉,文初提出的问题你也应该都懂了,接下来,面试你可以这样说。

快照读与当前读的区别?


01
事务隔离机制实现原理?

未提交读,直接返回最新记录的值,没有视图概念;提交读与可重复读是通过read-view不同生策略实现;串行化是通过加锁。


02
MVCC实现?

版本链+Read View


03
可重复读与提交读实现?

可重复读隔离级别下,事务开始时创建read view,之后一直用这个read view。提交读隔离界别下,每一个语句执行前都会重新算出一个新的视图。



04
Read View是怎么回事?

事务开启瞬间,会将当前活跃事务的trx_id记录到一个数组,数组最小事务ID记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位(分配给下一个事务的ID)

Read View由三部分组成:

1、当前活跃的事务ID列表【101,102】

2、低水位,活跃事务的最小值Tmin=102

3、系统中最大事务ID加一Tmax=103

MYSQL的隔离机制实现
最后
MYSQL的隔离机制实现

本篇的MYSQL的隔离机制实现就到这里啦,觉得不错的话,不要忘记点个赞~


小龙coding


大厂面试|内推分享|经验分享|技术交流