MySQL篇之MVCC

一、什么是MVCC

        全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突。

MySQL篇之MVCC_第1张图片

        事务5查询的记录是哪个事务版本的记录呢?MVCC的具体实现,主要依赖于数据库记录中的隐式字段、undo log日志、readView

二、MVCC实现原理

1.隐藏字段

        除了自己自定义的字段外,还有隐藏的3个字段。

MySQL篇之MVCC_第2张图片

        DB_TRX_ID:修改事务时,就会自增+1。

        DB_ROLL_PTR:就是指向上一个版本。

        DB_ROW_ID:当字段有主键时,这个隐藏字段就没有意义了。

2.undo log

(1)定义

        1. 回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

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

        3. 而update、delete的时候,产生的undo log日志不仅在回滚时需要,mvcc版本访问也需要,不会立即被删除。

(2)undo log版本链

        不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的部是最的旧记录,链表部是最的旧记录。

MySQL篇之MVCC_第3张图片

MySQL篇之MVCC_第4张图片

MySQL篇之MVCC_第5张图片

3.readView

(1)定义

        ReadView(读视图)快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

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

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

        不同隔离级别也不一样:

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

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

(2)四个核心字段

MySQL篇之MVCC_第6张图片

        用下图解释上面字段:因为事务5开始创建视图时,事务2已经结束了。

        m_ids就是345事务的id集合。                min_trx_id就是事务3的id。

        max_trx_id就是事务5的id+1。                creator_trx_id就是事务5的id。MySQL篇之MVCC_第7张图片

(3)版本链数据的访问规则

MySQL篇之MVCC_第8张图片

(4)隔离级别

        1. RC隔离级别下,在事务中每一次执行快照读时生成ReadView。MySQL篇之MVCC_第9张图片

        结合前面的undolog和访问规则:可以得出事务5查询的第一次记录是事务2提交后的记录,事务5第二次查询的是事务3提交后的记录MySQL篇之MVCC_第10张图片

MySQL篇之MVCC_第11张图片

       2. RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。MySQL篇之MVCC_第12张图片

三、面试的回答

面试官:事务中的隔离性是如何保证的呢?(你解释一下MVCC)

候选人:事务的隔离性是由锁和mvcc实现的。

其中mvcc的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为了三个部分,第一个是隐藏字段,第二个是undo log日志,第三个是readView读视图

隐藏字段是指:在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事务id),记录每一次操作的事务id,是自增的;另一个字段是roll_pointer(回滚指针),指向上一个版本的事务版本记录地址

undo log主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表

readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生成ReadView,后续复用。

你可能感兴趣的:(mysql,数据库,java,面试)