多版本并发控制指的就是维护一个数据的多个版本,,是得读写操作没有冲突;MVCC和锁(排他锁)也是事务隔离性的保证
就好比以下的例子,我们查询id为30的记录到底是查询的是哪个事务所有修改的数据呢?这个就是MVCC的特点了,MVCC可保证我们读写操作没有冲突
MVCC的具体实现,主要是依赖于数据库记录中的隐式字段、undo log日志、readView。下面就来介绍一下这几个组成作用都是什么
隐式字段
隐藏字段是指:在mysql中给每个表都设置了隐藏字段其中包括以下三种:
- DB_Trx_Id:最近修改事务的ID,记录插入这条记录或最后一次修改记录的事务ID
- DB_Roll_Ptr:回滚指针,只想这条记录的上一个版本,用于配合undo log,指向上一个版本
- DB_Row_Id:隐藏主键,如果表结构没有指定主键,那么将会自动生成一个隐藏字段
Undo Log
回滚日志,在insert、update、delete的时候产生一个与之相反的sql(如insert的命令则在日志中加一个delete语句),便于数据回滚的日志
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除
而update、delete的时候,产生的undo log日志不仅在回滚时需要,MVCC版本访问也需要,不会立即被删除
Undo log版本链
undo 日志版本链是指一行数据被多个事务依次修改过后,MySQL 会为每个事务保留修改前的数据 undo 回滚日志,并通过两个隐藏字段trx_id
(表示更新本行数据的事务 id)和roll_pointer
(表示回滚指针,它指向该行数据上一个版本的 undo 日志)将这些 undo 日志串联起来形成的一个历史记录版本链
以下就是上述例子中的undo log版本链:
不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录
ReadView
ReadView(读视图)是快照读Sql执行时MVCC提取提取数据的依据,记录并且维护当前活跃的事务(未提交的)id
当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都是一种当前读
快照读:简单的select(不加锁)就是快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读,在不同的隔离级别之下,生成快照读的时机是不同的
- Read Committed:每次select都会生成一个快照读
- Repeatable Read:开启事务后第一个select语句才是快照读的地方,后序会复用该快照读
在ReadView中包含四个核心字段:
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
以下是关于MVCC版本链数据访问规则:
-
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
中是可以访问该版本
成立,说明数据已经提交。
下面会以下述的事务执行顺序表来进行说明不同隔离级别的快照读
在RC的隔离级别下,每次select都会生成一个快照读,生成的快照如下:
根据版本链访问规则可知,第一次生成的快照读访问的是事务2,第二次生成的快照读访问的是事务3:
由此可知在RC级别下,可知每次快照读都是访问已经提交的事务
在RR的隔离级别下,只有事务第一次执行的时候会生成一个快照读,生成的快照如下:
可知两次select读取的都是事务2
总结
其中mvcc的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为了三个部分,第一个是隐藏字段, 第二个是undo log日志,第三个是readView读视图
隐藏字段是指:在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事 务id),记录每一次操作的事务id,是自增的;另一个字段是roll_pointer(回 滚指针),指向上一个版本的事务版本记录地址
undo log主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本, 通过roll_pointer指针形成一个链表
readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规 则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读 是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快 照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生 成ReadView,后续复用
标签:面试题,快照,trx,记录,事务,并发,版本,MVCC,id From: https://blog.csdn.net/loss_rose777/article/details/140503092