一、MVCC是什么意思?
MVCC:Multi-Version Concurrency Control,多版本并发控制。
二、MVCC是做什么的?
MVCC是一种并发控制方法,是一种提高并发的技术。在数据库中,大多数情况下替代锁的使用,提升事务之间的并发数。提升资源使用效率。
使用MVCC实现数据库中的不同的隔离级别,保存不同的数据版本,当事务进行并发访问的时候,使其只能看到相应隔离级别的数据版本。有效的提升数据库并发能力。
三、MySQL中Innodb的MVCC使用
1、MySQL的默认隔离级别是RR(Repeatable Read),可重复读。
注:ORACLE、SQLServer、Vertica的默认隔离级别为read committed,读提交。
2、MVCC是的InnoDB存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。未提交读隔离级别总是读取最新的数据行,无需使用MVCC;可串行化隔离级别需要对所有读取的行都加锁,单纯使用MVCC无法实现。
3、MVCC解决的问题是读写互相不阻塞的问题,用来实现数据库事务隔离级别的,减少锁的使用,提升并发,提高数据库性能。它通过保存数据在某个时间点的快照来实现的. 不同存储引擎的MVCC实现是不同的。
4、原理是在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号(可能为空,其实还有一列称为回滚指针,用于事务回滚)。这里的版本号并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。
重点:当前事务只能看到当前事务号大于等于创建时的版本号并且小于等于删除时的版本号的数据。(创建时版本号<=当前事务版本号<=删除时版本号)
四、举例说明
当前事务看到哪些数据的条件:
数据创建时版本号<=当前事务版本号<=数据删除时版本号
1、首先创建了一个表,如下:
create table psbc(
id int primary key auto_increment,
name varchar(20));
2、事务1先插入数据,如下:
假设事务id号为1:
start transaction;
insert into psbc values(NULL,‘cunqian’) ;
insert into psbc values(NULL,‘quqian’);
insert into psbc values(NULL,‘zhuanqian’);
commit;
对应的表数据如下:
id
name
创建时间(版本号)
删除时间(版本号)
1
cunqian
1
undefined
2
quqian
1
undefined
3
zhuanqian
1
undefined
3、事务2查询此表,如下:
start transaction;
select * from psbc; //(1)
select * from psbc; //(2)
commit;
假设一:
当事务2执行完第1步后,事务3执行了insert操作
start transaction;
insert into psbc values(NULL,‘gongzi’);
commit;
这时,表中如下:
id
name
创建时间(版本号)
删除时间(版本号)
1
cunqian
1
undefined
2
quqian
1
undefined
3
zhuanqian
1
undefined
4
gongzi
3
undefined
随后,事务2执行第二次查询,还是只能看到原来的3条记录,保持了查询一致性。
假设二:
当事务2执行完第1步后,事务3执行完后,事务4执行了delete操作
start transaction;
delete from psbc where id=1;
commit;
这时,表中如下:
id
name
创建时间
删除时间
1
cunqian
1
4
2
quqian
1
undefined
3
zhuanqian
1
undefined
4
gongzi
3
undefined
随后,事务2执行第二次查询,还是只能看到原来的3条记录,保持了查询一致性。
假设三:
当事务2执行完第1步后,事务3,4执行完后,事务5执行了update操作
start transaction;
update psbc set name=‘huaqian’ where id=2;
commit;
这时,表中如下:
id
name
创建时间(版本号)
删除时间(版本号)
1
cunqian
1
4
2
quqian
1
5
3
zhuanqian
1
undefined
4
gongzi
3
undefined
2
huaqian
5
undefined
随后,事务2执行第二次查询,还是只能看到原来的3条记录,保持了查询一致性。
总结:
无论有多少并发事务,在增、删、改中都会在隐藏列中记录相应的数据版本号。而对于不同的事务而言,在开启事务时都会分配一个自己的版本号,只要这个版本号大于等于每行数据创建时版本号并且小于等于每行数据删除时的版本号。就可以查看相应的数据。这样就减少了锁的使用,提升了并发能力,使各事务之间尽量互补干扰。