MVCC
1. 什么是MVCC?
多版本并发控制技术的英文全称是 Multiversion Concurrency Control,简称 MVCC 。

是通过保存数据在某个时间点的快照来实现并发控制的。也就是说,不管事务执行多长时间,事务内部看到的数据是不受其它事务影响的,根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。

可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。MVCC将数据库的行锁与行的多个版本结合起来,只需要很小的开销就可以实现读写不加锁,从而大大提高数据库系统的并发性能。

注意

写写情况还是需要加锁阻塞的。

MVCC并没有解决幻读问题。

2. MVCC解决什么问题?
通过 MVCC 可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。
因为 InnoDB 的 MVCC 采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
一致性读也被称为快照读,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。

 

3. MVCC如何工作?
MVCC保存某个时间点上的数据快照。一个事务内,看到的是同一个版本的快照,数据一致。不同事务在同一时间点看到的数据会不一致,因为他们得到的数据版本不一样。不同存储引擎的MVCC实现是不同的,典型的有乐观(optimistic)并发控制和悲观(pessimistic)并发控制。

隐藏字段
在InnoDB中,每个数据行记录除了一般数据列还包含下面几个隐藏字段:

DB_ROW_ID :6-byte,隐藏的行 ID,用来生成默认聚簇索引。如果我们创建数据表的时候没有指定聚簇索引,这时 InnoDB 就会用这个隐藏 ID 来创建聚集索引。

DB_TRX_ID :6-byte,操作这个数据的事务 ID,也就是最后一个对该数据进行插入或更新的事务 ID。这也是下面所说的修改版本号和删除版本号。

注意有1 bit用来标志是否被删除。

DB_ROLL_PTR :7-byte,回滚指针,也就是指向这个记录的 Undo Log 信息。

事务号
每开启一个事务,我们都会从数据库中获得一个事务 ID(也就是事务版本号),这个事务 ID 是自增长的,通过 ID 大小,我们就可以判断事务的时间顺序。

undo log
undo log即为回滚日志,每次事务在执行DML语句,便会将相反的DML写入undo log,等到事务RollBack时使数据恢复到事务最开始状态。

但是undo log除了回滚,还有一个作用:当前事务读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
MySQL之MVCC与幻读_并发控制

 

 

当隔离级别是REPEATABLE READ时,这种策略下,select、delete、 insert、 update语句如何操作:

SELECT 对于select语句,只有同时满足了下面两个条件的行,才能被返回:
行的修改版本号小于或者等于该事务号:这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
行的删除版本号要么没有被定义,要么大于事务版本号:
行的删除版本号如果没有被定义,说明该行没有被删除过;
如果删除版本号大于事务版本号,说明该行是被该事务后面启动的事务删除的,由于是repeatable read隔离等级,后开始的事务对数据的影响不应该被先开始的事务看见,所以该行应该被返回。
INSERT 对新插入的行,行的更新版本号被修改为该事务的事务号。
DELETE 对于删除,直接把该行的删除版本号设置为当前的事务号,相当于标记为删除,而不是实际删除。
UPDATE 在更新行的时候,InnoDB会把原来的行复制一份到回滚段中,并把当前的事务号作为该行的更新版本号,同时保存当前事务版本号到原来的行作为行删除标识:保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。
幻读
首先MySQL事务隔离级别默认是RR(可重复读),但是会导致幻读问题。