MVCC的庐山真面目

编程入门 行业动态 更新时间:2024-10-28 20:30:02

MVCC的<a href=https://www.elefans.com/category/jswz/34/1723803.html style=庐山真面目"/>

MVCC的庐山真面目

概念

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

使用MVCC的好处

  1. 多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
  2. 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题(后面解释)。

注意

  1. 本文讨论的MVCC是指Mysql搜索引擎inno DB的多版本并发控制。
  2. MVCC只解决快照读时的读写冲突,而不解决当前读操作时的读写冲突。当前读操作通过加锁的方式解决读写冲突。并且MVCC只作用于读提交和可重复读两个事务隔离级别,因为读未提交只读最新数据,不需要版本控制。可串行化通过加锁阻塞的方式控制读写冲突。
  3. 快照读:简单的select操作(当然不包括 select … lock in share mode, select … for update)。
  4. 当前读:select … lock in share mode、select … for update、insert、update、delete。
  5. 数据库生成事务ID是通过当前时间戳递增方式生成的。

小结

  1. MVCC可以无阻塞解决读(快照读)写冲突。但是如果是当前读,读写冲突还得使用锁解决解决。
  2. 读读冲突不需要额外处理。
  3. 写写冲突也需要锁。

原则
后面说‘读’,不特别说明,都是指快照读。当前读+写操作可以暂时统一理解为‘写’。

原理

MVCC的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖undo日志 、Read View 、每行记录中的 3个隐式字段(DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID)来实现的。

undo log

undo log记录了表数据的修改记录(insert、update、delete),形成版本链。可以支持回滚操作和快照读操作

undo log主要分为两种,仅update undo log支持MVCC:

  1. insert undo log
    代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
  2. update undo log
    事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除。

三个隐式字段的概念

  1. DB_TRX_ID:6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID。
  2. DB_ROLL_PTR:7byte,回滚指针,指向这条记录的上一个版本(构成版本链)。
  3. DB_ROW_ID:6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。

read view(读视图)

有了undo log提供的版本链和每行记录都存在的三个隐藏记录外,还需要生成read view作为版本链中某条记录是否可见的依据。

readview中四个比较重要的概念

  1. m_ids:表示在生成readview时,当前系统中活跃的读写事务id列表;
  2. min_trx_id:表示在生成readview时,当前系统中活跃的读写事务中最小的事务id,也就是m_ids中最小的值;
  3. max_trx_id:表示生成readview时,系统中应该分配给下一个事务的id值;
  4. creator_trx_id:表示生成该readview的事务的事务id;

有了readview,在访问某条记录时,按照以下步骤判断版本链中某个版本的记录是否可见

  1. 如果被访问版本的trx_id,与readview中的creator_trx_id值相同,表明当前事务在访问自己修改过的记录,该版本可以被当前事务访问;
  2. 如果被访问版本的trx_id,小于readview中的min_trx_id值,表明生成该版本的事务在当前事务生成readview前已经提交,该版本可以被当前事务访问;
  3. 如果被访问版本的trx_id,大于或等于readview中的max_trx_id值,表明生成该版本的事务在当前事务生成readview后才开启,该版本不可以被当前事务访问;
  4. 如果被访问版本的trx_id,值在readview的min_trx_id和max_trx_id之间,就需要判断trx_id属性值是不是在m_ids列表中?
    如果在:说明创建readview时生成该版本的事务还是活跃的,该版本不可以被访问
    如果不在:说明创建readview时生成该版本的事务已经被提交,该版本可以被访问;

小结
到这里我们明白了MVCC的机制,利用每行记录都有的三个隐藏字段得到当前记录的最新修改事务ID和版本链,结合生成read view时的事务ID(creator_trx_id)和read view中记录的当前活跃事务ID等信息,判断某行记录是否对当前快照读可见,达到目的。

读已提交和可重复读下的read view区别

在读已提交和可重复读中都使用MVCC控制,可为什么读已提交会造成不可重复读的问题呢?答案在生成read view的时机。

生成readview时机

  1. RC隔离级别:每次读取数据前,都生成一个readview。
  2. RR隔离级别:在第一次读取数据前,生成一个readview。

RR隔离级别表1和RC隔离级别表2中read view的生成时机对比
可以看到,表1在事务B开启的时候就自动执行了一次快照读,创建了read view,并且后续的select都使用这个read view。而表2在执行select前才创建read view,并且每次select前都创建一个新的read view。从上述的MVCC机制中可知,生成read view时机不一样,生成的当前活跃事务id列表也不一样,直接导致版本链数据可见性不一样,最终导致RR和RC两个隔离级别。

更多推荐

MVCC的庐山真面目

本文发布于:2024-02-11 12:58:53,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1681123.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:庐山真面目   MVCC

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!