MVCC:Multi-Version Concurrency Control 多版本并发控制。笔者用自己的话对MVCC做一个总结:通过某个时间点上的数据快照对数据的版本控制,目的是为了避免使用各种锁影响并发性能
●MySQL锁机制
说到锁,MySQL里提供了几种锁机制
读写锁
表锁 (MYISAM使用了表锁)
行级锁 (InnoDB使用了行级锁)
第一点:
MVCC并不是MySql独有的,Oracle,PostgreSQL等都在使用。
MVCC并没有简单地使用行锁,而是使用“行级别锁”(row-level locking)。
MVCC的基本原理是:
MVCC的实现,通过保存数据在某个时间点的快照来实现的。这意味着一个事务无论运行多长时间,在同一个事务里能够看到数据一致的视图。根据事务开始的时间不同,同时也意味着在同一个时刻不同事务看到的相同表里的数据可能是不同的。
MVCC的基本特征:
- 每行数据都存在一个版本,每次数据更新时都更新该版本。
- 修改时Copy出当前版本随意修改,各个事务之间无干扰。
- 保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)
InnoDB存储引擎MVCC的实现策略:
在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号(可能为空)。这里的版本号并不是实际的时间值,而是系统版本号。每开始 个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。
每个事务又有自己的版本号,这样事务内执行CRUD操作时,就通过版本号的比较来达到数据版本控制的目的。具体做法见下面的示意图。
MVCC具体的操作如下:
SELECT:InnoDB会根据以下两个条件检查每行记录:
1)InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,只么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
2)行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。
INSERT:InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
DELETE:InnoDB为删除的每一行保存当前系统版本号作为行删除标识。
UPDATE:InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当系统的版本号为原来的行作为删除标识。
保存这两个额外系统版本号,使大多数操作都可以不用加锁。这样设计使得计数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。
MVCC只在REPEATABLE READ和READ COMMITED两个隔离级别下工作,其它两个隔离级别和MVCC不兼容。
)
把及时总结当成一种习惯
mysql的mvcc(多版本并发控制)
我们知道,mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能。
什么是多版本并发控制呢 ?其实就是在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号,
而每一个事务在启动的时候,都有一个唯一的递增的版本号。
1、在插入操作时 : 记录的创建版本号就是事务版本号。
比如我插入一条记录, 事务id 假设是1 ,那么记录如下:也就是说,创建版本号就是事务版本号。
id | name | create version | delete version |
1 | test | 1 |
2、在更新操作的时候,采用的是先标记旧的那行记录为已删除,并且删除版本号是事务版本号,然后插入一行新的记录的方式。
比如,针对上面那行记录,事务Id为2 要把name字段更新
update table set name= ‘new_value‘ where id=1;
id | name | create version | delete version |
1 | test | 1 | 2 |
1 | new_value | 2 |
3、删除操作的时候,就把事务版本号作为删除版本号。比如
delete from table where id=1;
id | name | create version | delete version |
1 | new_value | 2 | 3 |
4、查询操作:
从上面的描述可以看到,在查询时要符合以下两个条件的记录才能被事务查询出来:
1) 删除版本号 大于 当前事务版本号,就是说删除操作是在当前事务启动之后做的。
2) 创建版本号 小于或者等于 当前事务版本号 ,就是说记录创建是在事务中(等于的情况)或者事务启动之前。
这样就保证了各个事务互不影响。从这里也可以体会到一种提高系统性能的思路,就是:
通过版本号来减少锁的争用。
另外,只有read-committed和 repeatable-read 两种事务隔离级别才能使用mVcc
read-uncommited由于是读到未提交的,所以不存在版本的问题
而serializable 则会对所有读取的行加锁。
参考:mysql 的MVCC(多版本并发控制):http://www.cnblogs.com/dongqingswt/p/3460440.html
多版本并发控制:http://blog.csdn.net/xifeijian/article/details/45230053