Mysql的MVCC的理解

MVCC全称是: Multiversion concurrency control,多版本并发控制,提供并发访问数据库时,对事务内读取的到的内存做处理,用来避免写操作堵塞读操作的并发问题。

什么是写操作阻塞读操作?

RR级别是无法解决幻读的,在一个事务两次查询会出现前后两次查询不一致的情况。RC解决不了不可重复读,注意与幻读的区别不可重复读是前后两次读的相同行的不一致,侧重点在修改,欢读侧重新增和删除。如何避免两次查询数据的不一致性呢?先了解下快照读和当前读。

当前读和快照读

当前读
像 sel ect lock in share mode (共享锁), sel ect for up date; up date; insert; delete (排他锁)这些操作都是一种当前读,读取的是记录的最新版本,读取时会对记录进行加锁,防止其他事物修改。

快照读
像不加锁的 sel ect 操作就是快照读,快照读的前提是隔离级别不是串行级别,串行级别所有操作都是成当前读,并锁整个表。快照读是解决写操作造成读堵塞的问题,提高并发性,快照读是基于 MVCC 实现的,MVCC 是行锁的一个变种,一种乐观锁的实现方式,避免了加锁操作,降低了系统开销。

实现数据一致性的方式

方式一: 基于悲观锁的并发控制,事务A先写操作时,给这些数据加上锁,事务B读操作的时候,就发现读取不了,必须等A操作完毕才能访问,这保证B不会读到一个不一致的数据,但是这个会影响程序的运行效率。

方式二:MVCC一种乐观锁的实现思想,每次读操作看到的都是某一特定时刻的数据库快照(Read View),写操作是操作当前最新版本也就是当前读,类似于读写分离的思想。在A事务没有提交之前,B始终读到的是某一特定时刻的数据库快照,不会读到B事务中的数据修改情况,直到B事务提交,才会读取B的修改内容。也就是一定要有个时间标识,在更新操作没有完成之前都是使用更新之前的数据。

MVCC的实现的两种方式
MVCC有两种实现方式,第一种实现方式是将数据记录的多个版本保存在数据库中,当这些不同版本数据不再需要时,有专门的回收线程来回收这些记录。PostgreSQL和Firebird/Interbase采用。

第二种实现方式只在数据库保存最新版本的数据,但是会在使用undo时动态重构旧版本数据,这种方式被Oracle和MySQL/InnoDB使用。对于旧数据的清理,数据并不是每次执行并不真正的删除,Mysql 的‬innodb处理‬模式‬是‬会开启一个后台线程执行清理工作,具体的规则是将删除“版本号”小于当前系统版本的行删除,这个过程叫做purge。后续‬会‬讲到‬版本号‬。

Innodb下的MVCC的实现机制
InnoDB的MVCC是在每行记录后面保存两个隐藏的列来实现:一个保存了行的创建时间(本质‬是‬‬单向‬递增‬的事务‬‬ID‬),一个保存行的过期时间(删除时间,单向‬递增‬的‬事务‬ID)。在RR隔离级别下,MVCC的操作如下:

sel ect操作。InnoDB只查找版本早于(包含等于)当前事务版本的数据行。可以确保事务读取的行,要么是事务开始前就已存在,或者事务自身插入或修改的记录。行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取的行,在事务开始之前未删除。
insert操作。将新插入的行保存当前版本号为行版本号。
delete操作。将删除的行保存当前版本号为删除标识。
up date操作。变为insert和delete操作的组合,insert的行保存当前版本号为行版本号,delete则保存当前版本号到原来的行作为删除标识。
例子
创建一个表user表,一个事务查询,另一个事务模拟插入,删除,更新等操作,看mvcc的如果根据版本号来解决数据不一致的

Mysql的MVCC的理解
建表语句

第一个事务ID为1

Mysql的MVCC的理解
事务ID 1

第二个事务

Mysql的MVCC的理解
事务ID 2

假设1

  假设在执行这个事务ID为2的过程中,刚执行到(1),这时,有另一个事务ID为3往这个表里插入了一条数据; 第三个事务ID为3;

Mysql的MVCC的理解
事务ID 3


  然后接着执行事务2中的(2),由于id=2的数据的创建时间(事务ID为3),执行当前事务的ID为2,而InnoDB只会查找事务ID小于等于当前事务ID的数据行,所以id=2的数据行并不会在执行事务2中的(2)被检索出来,在事务2中的1条sel ect

假设2

  假设在执行这个事务ID为2的过程中,刚执行到(1),假设事务执行完事务3后,接着又执行了事务4;   第四个事务:

Mysql的MVCC的理解
事务ID 4

接着执行事务ID为2的事务(2),根据sel ect 检索条件可以知道,它会检索创建时间(创建事务的ID)小于当前事务ID的行和删除时间(删除事务的ID)大于当前事务的行,而id=2的行上面已经说过,而id=1的行由于删除时间(删除事务的ID)大于当前事务的ID,所以事务2的(2)sel ect * from user也会把id=1的数据检索出来.所以,事务2中的两条sel ect 语句检索出来的数据都是1条数据。

版权申明:本站文章均来自网络,如有侵权,请联系01056159998 邮箱:itboby@foxmail.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

猜你还会喜欢下面的内容

    无相关信息

中国领先的互联网域名及云服务提供商

为您提供域名,比特币,P2P,大数据,云计算,虚拟主机,域名交易最新资讯报道

域名注册云服务器