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上一条记录,直到查找到合适读的版本号

 

 

参考自: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

原文地址:http://www.cnblogs.com/mumayiren/p/16861738.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性