基本概念
MVCC:全称Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现
MVCC提供了- -个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。
当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:
select .. lock in share mode(共享锁), select ... for update、update、 insert、 delete(排他锁)都是一 -种 当前读。
快照读:简单的select (不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
Read Committed:每次select, 都生成一一个快照读。
Repeatable Read:开启事务后第一 个select语句才是快照读的地方。
Serializable: 快照读会退化为当前读。
实现原理
一、数据库在每张表内都维护了三个隐藏字段
1,DB_TRX_ID:最近修改事务,记录插入这条记录或最后一次修改该记录的事务id。
2,DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。
3,DB_ROW_ID:隐藏主键,如果表结构没有指定主键,将会自动生成该字段。
二、undo log:回滚日志,在insert,update,delete的时候产生的便于数据回滚的日志。当insert的时候,产生的undo log只在回滚时需要,在事务被提交后,可立即被删除。而update,delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
问题是:在查询的时候,返回的是undo log中哪个版本呢? 这个不是由版本链控制的,具体要返回哪个版本又涉及到MVCC实现原理的第三个组件,readView
三、readView : ReadView读视图是快照都SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id,ReadView中包含四个核心字段
1、m_ids:当前活跃的事务id集合
2、min_trx_id:最小活跃事务id
3、max_trx_id:预分配事务id,当前最大事务id+1,因为事务id是自增的
4、creator_trx_id:ReadView创建者的事务id
版本链数据访问规则:如果事务id为trx_id来进行查询,要遵循如下规则。
1、 trx_id == creator_trx_id , 说明数据是当前这个事务更改的,则可以访问该版本
2、trx_id < min_trx_id , 说明数据已经提交了,可以访问该版本
3、trx_id > max_trx_id ,说明事务是在readView生成后才开启的,不可以访问该版本
4、min_trx_id <= trx_id <= max_trx_id ,而且trx_id 不在m_ids中,说明数据已经提交,可以访问该版本
另外要注意的是,不同的隔离级别,生成ReadView的时机不同,read committed是在事务中每一次执行快照读时生成readview,repeated read仅在事务中第一次执行快照读时生成readView,后续复用该readView。
先以RC为例,如下图
在RR中,用的都是同一个ReadView,所以查询到的数据也是一样的,这也是为什么RR解决了不可重复读的原因。
标签:事务,快照,记录,什么,MVCC,trx,版本,MYSQL,id From: https://www.cnblogs.com/tyleaf/p/17026414.html