多版本并发控制
mysql的innodb采用的是行锁,并且采用了多版本并发控制来提高读操作的性能。这里简单谈一下我对repeatable read隔离级别下,一些事务操作结果的理解。
以下是在《高性能Mysql》一书上看到的原话:
在很多博客里看到说保存事务版本号作为标识,我认为这个说法是不对的,应该是书上所说的保存系统版本号作为标识。看下面的例子。
首先创建表
CREATE TABLE t (a INT);
例1:
事务T1 |
start transaction; //事务版本号为1,系统版本号为2 |
insert into t select 1; |
insert into t select 2; |
insert into t select 3; |
Commit; |
t表
a | Create version | Delete version |
1 | 1 |
|
2 | 1 |
|
3 | 1 |
|
事务T2 | 事务T3 |
start transaction; //事务版本号为2 |
|
| start transaction; //事务版本号为3 |
Delete t where a = 1; |
|
| Select * from t; |
Commit; |
|
| Select * from t; |
| Commit; |
t表
a | Create version | Delete version |
1 | 1 | 4 |
2 | 1 |
|
3 | 1 |
|
在repeatable read下,事务T3两次读到的数据结果一定是相同的,之所以第二次能读到a=1的数据是因为a=1的删除版本号是系统版本号3,而不是T2的事务版本号2;
例2:
一段时间后,当前没有事务引用的情况下,具有删除版本的数据会被真正删除,这是purge做的。
事务T4 | 事务T5 |
start transaction; //事务版本号为4 |
|
| start transaction; //事务版本号为5 |
Update t set a = 5 where a = 2;//获得写锁 |
|
| Update t set a=6 where a = 2;//写锁被事务T4获得,语句阻塞 |
Commit;//释放写锁 |
|
| //上一条语句执行,但是此时由于t表中a=2的数据已经有删除版本号了,此语句不改变t表数据 |
| Select * from t;//可以读到a=2的数据 |
| Commit; |
t表
a | Create version | Delete version |
2 | 1 | 6 |
5 | 6 |
|
3 | 1 |
|
第一次写博客,有理解不对的地方请指正,轻喷