MVCC
全名叫做:多并发版本并行(concurrent)控制
是一种并发控制方法
再MySQL InnoDB的实现主要是为了提高数据库并发性能,处理读-写冲突
MVCC知识一个抽象概念,而在MySQL中,快照读就是MySQL实现MVCC模型的一个非阻塞读功能(相对而言,当前读就是悲观锁的具体实现)
当前读和快照读
-
当前读:加悲观锁
-
select lock in share mode
-
select for update
-
update/insert/delete
-
-
快照读
-
不加锁的select就是快照读,即不加锁的非阻塞读
-
快照读的实现是基于MVCC(可以认为其是行锁的一个变种,很多情况下避免了加锁操作)
-
由于是基于多版本,快照读读到的并不一定是数据的最新版本,而有可能是历史版本
-
MVCC的能解决的问题
数据库并发三种场景
-
读-读:不需要并发控制
-
读-写:隔离性问题,脏读,幻读,不可重复读
-
写-写:可能存在更新丢失问题,需要加悲观锁或者乐观锁
MVCC就是用来解决读-写冲突的无锁并发控制
-
为事务分配单项增长的时间戳,为每个修改保存一个版本
-
版本与事务时间戳关联,读操作只读事务开始前数据库的快照
-
可以解决脏读,幻读,不可重复读等读写隔离问题,但是不能解决更新丢失问题(写写隔离)
MVCC的实现原理
其实现大概依赖三部分
-
3个隐式字段:每一行除了用户自定义的字段外,还有数据库隐式定义的,用来记录事务的时间戳
-
DB_TRX_ID:最近一次修改这条记录的事务ID
-
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本(指向undo日志里)
-
DB_ROW_ID:隐含的自增id(隐藏逐渐),如果没有主键,InnoDB会自动以这个字段产生一个聚簇索引
-
-
undo日志:主要分为两种
-
插入undo日志,事务提交之后就可以丢掉的,因为没有读写冲突,这部分只负责事务回滚
-
update undo日志,包括update和delete,因为有读写冲突,所以还要另外负责处理读写冲突
-
-
Read View:读视图,其实就是所谓的快照
-
每个事务在开启的时候都会被分配一个id(自增)
-
在事务进行快照读的时候产生Read View,记录并维护系统当前活跃事务的id
-
Read View主要是用来做可见性判断的,执行快照读的时候来判断当前事务能看到哪个版本的数据,有可能是最新版本,也有可能是undo log中某个旧版本
-
维护四个内容
-
id_list生成快照时,系统中活跃的事务id列表
-
m_trx_id:当前活跃事务最小的id
-
max_trx_id:下一个将要分配的事务id
-
creator_trx_id:声称该ReadView事务的事务id
-
-
第一次快照读某个数据的时候生成Read View(快照),然后之后每次再读取这行数据的时候,都会根据之前生成的这个快照来判断版本号,确定哪个版本是可读的,哪个版本是不可读的
当某个事务想要读取某一行数据时,MVCC判断哪个版本对当前事务是可见的过程:
-
从版本链开始获取记录,记为id(查每行记录的DB_TRX_ID,看最后一次修改这行数据的事务)
-
如果这个id==creator_trx_id,说明上一次修改是本事务,可以直接读取
-
如果这个id<min_trx_id,说明上一次修改这行数据的事务已经被提交了(或者说成生成这个版本的时间在生成快照之前),这个版本可以被当前事务访问
-
如果这个id>=max_trx_id,说明上一次修改这行数据的事务在生成Read View之后才开启,这个版本不可以被当前事务访问(否则会造成不可重复读),需要根据链表指针,找到下一个版本,重复这个步骤
-
最后还要查一下是否在活跃事务列表里(因为这个事务可能加载一大一小之前,但是很早之前就commit了,生成快照的时候不活跃,和<min_trx_id的情况是一样的),如果在列表里,说明这个版本是不可访问的,因为这是其他事务未提交的数据
附一张流程图吧
总结一下,事实上快照就相当于记录了一下快照读时各个事务的状态,记录了两个边界情况和一个活跃队列,目的都是为了定位后面读取时的版本号和当前事务的相对时间关系,而版本号的表示是通过最后一次修改该行的事务id和它之后的那条链表
-
如果在生成快照的时候已经提交了,当然没问题,这包括两种情况,小于最小id和不在活跃队列中都是这个情况(我认为最小id是为了减小检查这个list的次数)
-
如果在生成快照的时候还未提交(查版本号找到的最近一次修改该行的事务id发现的),就需要查找undo log上一条记录,直到查找到合适读的版本号
再加一点:
MVVC是用来解决读写隔离的,读写隔离有四个等级,串行化是使用了行锁,读取未提交没有做读写隔离
-
read-committed:每次读取的时候都生成Read View,所以可能导致不可重复读
-
repeatable read:每次读取都根据第一次快照读的Read View,所以每次都是读取到同一个版本号
参考自:https://blog.csdn.net/zzti_erlie/article/details/110454543?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166761746016800182734227%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166761746016800182734227&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-110454543-null-null.142^v63^opensearch_v2,201^v3^control_2,213^v1^control&utm_term=MVCC&spm=1018.2226.3001.4187
标签:事务,快照,MVVC,学习,Read,理解,版本,MVCC,id From: https://www.cnblogs.com/mumayiren/p/16861738.html