MVCC实现机制

1. MVCC简介

1.1 什么是MVCC

  MVCC(Multiversion concurrency control )是一种多版本并发控制机制。

1.2 MVCC是为了解决什么问题?

  并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。
  大家都应该知道,锁机制可以控制并发操作,但是其系统开销较大,而MVCC可以在大多数情况下代替行级锁,使用MVCC,能降低其系统开销。

1.3 MVCC实现

  MVCC是通过保存数据在某个时间点的快照来实现的。不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制。当我们创建表完成后,mysql会自动为每个表添加 数据版本号(最后更新数据的事务id)db_trx_id 删除版本号 db_roll_pt (数据删除的事务id) 事务id由mysql数据库自动生成,且递增。

2.MVCC 具体实现分析

2.1 MVCC逻辑流程-插入(insert)

  如下图,同一事务中(假设事务id=1)插入两条记录,记录的数据版本号为事务id=1,删除版本号为null

start transaction;(事务id为1)
INSERT INTO user (name,sex) VALUES ('张三','');
INSERT INTO user (name,sex) VALUES ('李四','');
commit;

  对应在数据中的表如下(后面两列是隐藏列,我们通过查询语句并看不到)

  

2.2 MVCC逻辑流程-查询(select)

  查询时需要同时满足以下两个条件
  1、查找数据版本号,早于(小于等于)当前事务id的数据行。 这样可以确保事务读取的数据是事务之前已经存在的。或者是当前事务插入或修改的。
  2、查找删除版本号为null 或者大于当前事务版本号的记录。 这样确保取出来的数据在当前事务开启之前没有被删除。

  如下图,假如有一个事务中执行查询(假设事务id=2)

start transaction;(事务id为2)
select * from user where sex = '';  --(1select * from user where sex = '';  --(2commit;

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

start transaction;(事务id为3)
INSERT INTO user (name,sex) VALUES ('王五','');
commit;

  此时表中的数据如下:

  

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

  

2.3 MVCC逻辑流程-删除(delete)

  如下图,假如有一个事务中执行查询(假设事务id=4)

start transaction;(事务id为4)
select * from user where sex = '';  --(1)
select * from user where sex = '';  --(2)
commit;

  假设事务 id=4 刚执行到(1),此时有另外一个事务 id=5 执行了删除语句,会更新数据的删除版本号为当前事务id = 5 

start transaction;(事务id为5)
DELETE FROM user WHERE id = 1;
commit;

  此时数据库表中数据如下:

  

  接着执行事务 id=4的事务(2),根据SELECT 检索条件可以知道,它会检索创建时间(创建事务的ID)小于当前事务ID的行和删除时间(删除事务的ID)大于当前事务的行,表中id=1的行由于删除时间(删除事务的ID)大于当前事务的ID,所以事务 id=2 的(2)在执行的时候也会把表中 id=1 的数据检索出来,所以事务4中的两条select 语句检索出来的数据都如下:

  

2.4 MVCC逻辑流程-修改(update)

  可以理解为,当一个事务中 修改一条记录时, 是先复制该数据,新数据数据版本号为当前事务id,删除版本号为 null 。然后更新 原来数据的删除版本号为 当前事务id。如下:

  假如一个事务 id=6 执行了一条update语句

start transaction;(事务id为6)
UPDATE user SET name='李四1' WHERE id = 2
commit;

  执行结果如下:

  

 

 

 

 

 

posted @ 2019-08-14 15:21  路常有  阅读(8156)  评论(1编辑  收藏  举报