mysql数据库系列-MySQL系列MySQL

MySQL——MVCC--多版本并发控制机制

2021-01-15  本文已影响0人  小波同学

前言

以下的分析均在mysql的InnoDB引擎下。假设此时事务A与事务B同时执行。

一、定义:

MVCC(Multi-Version Concurrency Control,多版本并发控制)一种并发控制机制,在数据库中用来控制并发执行的事务,控制事务隔离进行。

二、核心思想:

MVCC是通过保存数据在某个时间点的快照来进行控制的。使用MVCC就是允许同一个数据记录拥有多个不同的版本。然后在查询时通过添加相对应的约束条件,就可以获取用户想要的对应版本的数据。

三、基本数据结构

1、redo log:

重做日志记录。存储事务操作的最新数据记录,方便日后使用。

2、undo log

撤回日志记录,也称版本链。当前事务未提交之前,undo log保存了当前事务的正在操作的数据记录的所有版本的信息,undo log中的数据可作为数据旧版本快照供其他并发事务进行快照读。每次有其它事务提交对当前数据行的修改,都是添加到undo log中。undo log是由每个数据行的多个不同的版本链接在一起构成的一个记录“链表”。如下图:

3、read_view(快照)

①read_view的简单理解:

会对数据在每个时刻的状态拍成照片记录下来。那么之后获取某时刻的数据时就还是原来的照片上的数据,是不会变的。其实也可以简单理解为是一个版本链的集合,只不过在这里的版本链是经过筛选的。

②read_view的基本结构:

read_view->creator_trx_id = 当前事务id; # 当前的事务id
read_view->up_limit_id = 12654;        # 当前活跃事务的最小id
read_view->low_limit_id = 12659;       # 当前活跃事务的最小id
read_view->trx_ids = [12654, 12659];   # 当前活跃的事务的id列表,又称活跃事务链表。表示在记录当前快照时的所有活跃的、未提交的事务
read_view->m_trx_ids = 2;              # 当前活跃的事务id列表长度

注意:

③read_view的记录筛选方式:

前提:DATA_TRX_ID 表示每个数据行的最新的事务ID;up_limit_id表示当前快照中的最先开始的事务;low_limit_id表示当前快照中的最慢开始的事务,即最后一个事务。

④read_view的更新方式:

注意:仅分析RC级别和RR级别,因为MVCC不适用于其它两个隔离级别。

注意:通过对read view的更新方式的分析可以得出:对于InnoDB下的MVCC来说,RR虽然比RC隔离级别高,但是开销反而相对少(因为不用频繁更新read_view)。

read_view的详细分析:https://www.iteye.com/blog/mahl1990-2347029

四、MVCC在mysql的具体实现:

4.1、基本数据结构的定义:

在mysql中,在实现MVCC时,会为每一个表添加如下几个隐藏的字段:

MVCC在二级索引结构下的分析:https://www.cnblogs.com/stevenczp/p/8018986.html

4.2、增删改查:

①增加:INSERT
②删除:DELETE
③修改:UPDATE <==> INSERT + DELETE
④查找:SELECT

注意:

五、使用MVCC核心优势:

六、MVCC与四大隔离级别的关系的分析:

分析了在MVCC的控制之下,如何实现四大隔离级别。

6.1、Read Uncimmitted级别:

由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC。原因是MVCC的DATA_TRX_ID只有在事务提交之后才会更新,而在Read uncimmitted级别下,由于是读取未提交的,所以说MVCC在这个级别下是不适用的。

6.2、Read Committed级别:

查找操作:
分析:假设当前有事务A、事务A+1、数据B(DATA_TRX_ID为A-1)。

6.3、Repeatable Read级别:

查找操作:
分析:假设当前有:事务A、事务A+1,数据B(DATA_TRX_ID为A-1)。

6.4、Serialization级别:

串行化由于是会对所涉及到的表加锁,并非行锁,自然也就不存在行的版本控制问题

总结:通过上面的分析可得:MVCC只适用于MySQL隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read)

七、MVCC、gap锁解决幻读问题的分析:

前提:InnoDB引擎、RR隔离级别(gap锁只存在于这个级别下)

7.1、首先了解数据记录的读取方式:快照读和当前读

①快照读:

读快照,可以读取数据的所有版本信息,包括旧版本的信息。其实就是读取MVCC中的read_view,同时结合MVCC进行相对应的控制;

select * from table where ?;
②当前读:

读当前,读取当前数据的最新版本。而且读取到这个数据之后会对这个数据加锁,防止别的事务更改。

(分析:在进行写操作的时候就需要进行“当前读”,读取数据记录的最新版本)

select * from table where ? lock in share mode;  # 读锁
select * from table where ? for update;          # 写锁
insert into table values (…); 
update table set ? where ?; 
delete from table where ?;

详见:https://www.jianshu.com/p/27352449bcc0

③RC和RR隔离级别下的快照读和当前读:

7.2、解决幻读问题:

7.3、特殊语句分析:

“MVCC不能根本上解决幻读的情况?”

分析:这句话的含义是指对于快照读,那么是可以通过MVCC来解决的;但是对于当前读,则必须通过next-key锁(行锁+gap锁)来解决。

参考:
https://www.cnblogs.com/axing-articles/p/11415763.html

上一篇 下一篇

猜你喜欢

热点阅读