什么是MVCC

Multiversion concurrency control (多版本并发控制)

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。不仅是MySQL,包括Oracle、PostgreSQL等其他数据库系统也都实现了MVCC,但各自的实现机制不尽相同,因为MVCC没有一个统一的实现标准。

可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。

MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的.

并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理,以达到用来避免写操作的堵塞为目的,从而引发读操作的并发问题.

其实就是在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号,而每一个事务在启动的时候,都有一个唯一的递增的版本号。

实现方式

创建InnoDB表之后它会默认的给你每行加隐藏的列:

DB_TRX_ID 数据行的版本号,是记录插入数据库的版本号

DB_ROLL_PT 删除版本号,

MVCC多版本并发控制_数据

插入数据

InnoDB为新插入的每一行保存当前系统版本号作为行版本号。

假设系统的全局事务id从1开始

begin:  -- 拿到系统的事务的ID=1;

insert into teacher(name,age) value (‘seven’,18)

insert into teacher(name,age) value (‘qingshan,19)

commit;

结果:

MVCC多版本并发控制_版本号_02

数据行的版本号就是事务id9

删除数据

InnoDB为删除的每一行保存当前系统版本号作为行删除标识。

MVCC多版本并发控制_数据_03

数据的删除

假设系统的全局事务id目前到了22

begin; -- 拿到系统的事务id = 22

delete teacher where id = 2 ;

commit ;

它会给删除的版本号记录成当前事务的id号

MVCC多版本并发控制_数据_04

修改数据

修改操作

假设系统的全局事务id号目前到了33

begin ; -- 拿到系统的事务id = 33

update teacher set age = 19 where id = 1 ;

commit ;

修改操作是先做命中的数据行,进行copy,将原来的行的数据的删除版本号的值设置为当前事务id(33)

修改之前:

MVCC多版本并发控制_mvc_05

修改之后:

MVCC多版本并发控制_版本号_06

select操作

MVCC多版本并发控制_数据_07

查询操作

假设系统的全局事务id号目前到了44


begin ; -- 拿到系统的事务id = 44 ;

select * from users ;

commit ;

数据库查询规则

在查询时要符合以下两个条件的记录才能被事务查询出来:

  1. 删除版本号 要么大于 当前事务版本号,要么就是未定义,这样确保删除操作在事务开始之前没被删除,是在当前事务启动之后做的.
  2. 创建版本号 小于或者等于 当前事务版本号 ,也就是,行的系统版本号小于或等于事务的系统版本号,,这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。

这样就保证了各个事务互不影响。从这里也可以体会到一种提高系统性能的思路,就是通过版本号来减少锁的争用。

查找删除版本号要么为null,要么大于当前事务版本号的记录,确保取出来的行记录在事务开启之前没有被删除.

MVCC多版本并发控制_数据_08