mysql之MVCC

1、概念

mvcc作用在于解决并发条件下,读写冲突的问题。一般用于RC和RR隔离级别,解决脏读和不可重复读的问题。

(1)当前读

读取的是记录的最新版本,读取时还要保证其他事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都是一种当前读。

(2)快照读

简单的select 就是快照读,读取的是记录的可见版本, 有可能是历史数据,不加锁,不阻塞

Read Committed:每次select,都会生成一个快照读

Repeatable Read:开启事务后第一个select语句才是快照读的地方。

Serializable:快照读会退化为当前读。

 2、MVCC的条件

要实现MVCC,需要3个条件:3个隐藏字段,undo log以及readview。

(1)隐藏字段

表结构中除了行数据以外,还有3个隐藏字段:

DB_TRX_ID:最新修改的事务ID,记录插入和修改最后一次的事务ID

DB_ROLL_PTR :回滚指针,指向上一个版本记录

DB_ROW_ID:隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。

(2)undo log

回滚日志,在insert update delete语句执行时保存回滚的日志。

当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。

而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即 被删除。

不同事务对同一条记录进行修改后,会生成一条版本连,下图为undo log中记录的版本链。

mysql之MVCC_第1张图片

 (3)readview

ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据。

readView包含四个核心字段:

m_ids:当前活跃的事务ID集合

min_trx_id:最小活跃事务ID

max_trx_id:预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)

creator_trx_id:ReadView创建者的事务ID

在readview中就规定了版本链数据的访问规则:

trx_id == creator_trx_id:可以访问该版本 成立,说明数据是当前这个事 务更改的。

trx_id < min_trx_id :可以访问该版本  成立,说明数据已经提交了。 

trx_id > max_trx_id:不可以访问该版本 成立,说明该事务是在 ReadView生成后才开启。

min_trx_id <= trx_id <= max_trx_id:如果trx_id不在m_ids中, 是可以访问该版本的 成立,说明数据已经提交。

 不同的隔离级别,生成readview的时机不一样:

READ COMMITTED :在事务中每一次执行快照读时生成ReadView。

REPEATABLE READ:在事务第一次执行快照读的时候生成ReadView。

3、原理分析

(1)RC隔离分析

RC隔离级别是解决脏读。在事务提交之后才能读到修改后的记录。这个是怎么做到呢,以下图为例子,事务5在每次快照读的时候都会生成一个readview。

mysql之MVCC_第2张图片

 根据undo log版本链记录和readview的匹配规则,我们来分析以下,事务5第一个查询,获取的结果是哪一个呢?

mysql之MVCC_第3张图片

按照上图中DB_TRX_ID为4,和事务5的第一次查询的readview进行对比,发现1,2,3,4都不匹配。

然后匹配下一条,DB_TRX_ID为3,和事务5的第一次查询的readview进行对比,发现1,2,3,4都不匹配。

然后匹配下一条,DB_TRX_ID为2,和事务5的第一次查询的readview进行对比,发现第二个是匹配的。那就说明此快照读,返回的是此版本链的数据。

事务5第二个查询,获取的结果是哪一个呢?

mysql之MVCC_第4张图片

按照上图中DB_TRX_ID为4,和事务5的第二次查询的readview进行对比,发现1,2,3,4都不匹配。

然后匹配下一条,DB_TRX_ID为3,和事务5的第二次查询的readview进行对比,发现第二个是匹配的。那就说明此快照读,返回的是此版本链的数据。

(1)RR隔离分析

RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。 而RR 是可 重复读,在一个事务中,执行两次相同的select语句,查询到的结果是一样的。以下图为例子,事务5在第一次快照读的时候会生成一个readview,后面就会服用此readview。上述已经分析过每次查询的记录在undo log中DB_TRX_ID为2的版本链是匹配的。

mysql之MVCC_第5张图片

 总结:

MVCC使用隐藏字段、undo log,readview实现的,没修改一次都会在undo log中生成一个版本记录,对于同一条记录会生成一个版本链,每条记录中包含隐藏字段。而readview则是在每次快照读的时候生成,通过版本链中的trx_id字段,对比readview中的记录,通过readview的规则,判断哪条版本记录是匹配的,从而得到最终结果。所以MVCC+锁实现了事务的隔离性。

你可能感兴趣的:(mysql,mysql,sql,数据库)