您的位置:首页 > 其它

不同事务隔离等级下的MVCC实现

2015-01-09 18:17 148 查看
http://blog.sina.com.cn/s/blog_502c8cc40100y0wj.html

MVCC由于其实现原理,只支持read
committed和repeatable read隔离等级,下面分别举例详细说明:

每次开始之前,都先执行如下的语句:

create database if not exists mydb;

use mydb;

drop table if exists emp;

create table `emp` ( `empno` int(11) not null auto_increment, `ename` varchar(20) default null, Primary key (empno)) engine=innodb default charset=gbk;

insert into emp values(100, "yuxiangang") ;

insert into emp values(200,"2zhaoyinggang");

insert into emp values(300,"3yihongbin");

3.1 read committed隔离等级

说明:session 1和session
2表示访问同一个数据库的两个不同的会话.行号用来代表不同的语句执行的时间点.
行号
session 1
session 2
1
set transaction isolation level read committed;
 
2
start transaction;
 
3
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1yuxiangang  |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin  |

+-------+-------+
 
4
 
set transaction isolation level read committed;
5
 
start transaction;
6
 
update emp set ename=1 where empno=100; 

delete from emp where empno=200;
说明: 修改一行,然后删除一行,但是事务不提交.
7
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1yuxiangang  |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin  |

+-------+-------+
 
说明:会话2的事务没有提交,所以会话1看不到会话2的事务对数据库数据的修改.但是实际上修改已经发生,会话1获取的被修改或者删除的数据,都来自于回滚段.这是通过MVCC来实现的.
8
 
commit;
说明: 会话2提交
9
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   300 | 3yihongbin  |

+-------+-------+
 
说明:当事务2提交以后,由于会话1采用的是read
committed隔离等级,所以会话2的提交马上会被会话1的事务看见.对于会话1来说,第一次执行select
* from emp where empno>=100;与第二次执行该语句,两次看到的结果不一样,第一次读看到了3行,第二次只看到了2行,就像发生了幻觉,称之为幻读;第一次看到100对应的ename为1yuxiangang,第二次看到的100对应的是1,两次获取的数据内容不一样,称之为不可重复读.
3.2 repeatable read隔离等级

注意:先执行开头的所有sql语句.
行号
session 1
session 2
session 3
session 4
1
set transaction isolation level repeatable read;
 
 
 
2
start transaction;
 
 
 
3
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1yuxiangang |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin |

+-------+-------+
 
 
 
4
 
 
 
set @@session.autocommit=1;
说明: 这里让会话4可以自动提交,便于观察它对前面3个会话的影响
 
 
 
 
update emp set ename=1 where empno=100; 

insert into emp values(400,"4chj");
说明: 会话4先更新一行数据,然后插入一行数据,并自动提交
5
select * from emp where empno>=100; 

查询的结果为: +-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1yuxiangang |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin |

+-------+-------+
 
 
 
说明: 会话1执行查询,两次查询得到的结果一样.它看不到会话4对数据库的修改,虽然会话4的事务已经提交.这是因为会话4的事务是在会话1的事务之后才开始.从这里也可以看出,repeatable
read实现了可重复读
6
 
set transaction isolation level repeatable read;start transaction;
 
 
7
 
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin  |

|   400 | 4chj  |

+-------+-------+
 
 
说明: 会话2是在会话4之后开始的,所以它看到了会话4对数据库的修改.同时可以看到,相同的查询语句,不同的事务来执行的时候,得到的结果不一样.会话2与会话3执行相同的查询就得到不一样的结果.
8
 
 
 
update emp set ename=2 where empno=200;
9
 
 
set transaction isolation level repeatable read;start transaction;
 
10
 
 
select * from emp where empno>=100;查询的结果为: 

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4chj  |

+-------+-------+
 
说明: 同样,这个会话查询到的结果与会话1和会话2的结果也不一样.而且会话3看到了会话4对数据库的修改.
11
 
 
 
update emp set ename=4 where empno=400;
12
 
 
 
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4     |

+-------+-------+
说明: 事务总是可以看到自身对数据库数据的修改,尽管别的事务可能看不到这种修改
13
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1yuxiangang |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin |

+-------+-------+
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2zhaoyinggang  |

|   300 | 3yihongbin  |

|   400 | 4chj  |

+-------+-------+
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4chj  |

+-------+-------+
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4     |

+-------+-------+
说明: 从上面的结果可以很清晰的看到:会话1,2,3,4执行相同的语句,即使是在同一时刻,他们看到的数据都可能不一样:对于empno为100的行,有 100  1yuxiangang 和 100
 1两个版本;对于empno为200的行,有 200
 2zhaoyinggang 和200  2两个版本…,而每一行数据都可能存在多个版本,那么这些行组合起来得到的结果集的版本就更是不计其数,这就是数据库多版本的由来.MVCC就是通过事务发生的不同的时间点,与数据行的版本来进行对比,从而取回与事务开始的时间点相一致的数据,来实现非阻塞的一致读.
14
commit;
commit;
commit;
commit;
15
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin |

|   400 | 4     |

+-------+-------+
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4     |

+-------+-------+
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4     |

+-------+-------+
select * from emp where empno>=100; 

查询的结果为:

+-------+-------+

| empno | ename |

+-------+-------+

|   100 | 1     |

|   200 | 2     |

|   300 | 3yihongbin  |

|   400 | 4     |

+-------+-------+
说明: 当所有事务都提交后,他们看到的结果都是一样的

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: