证明一个操作的一致性读过程是以自己开始执行的时间为准回滚的不是以该操作所在的事务开始的时间为准回滚的
初始条件:
SQL〉select * from test;
ID NAME
--- -----------
1 a
2 b
3 c
开始实验:
会话1:
SQL〉set time on
10:22:22 SQL〉update test set name=‘time’ where id=1;//按时间顺序为第二个操作
已更新1行
10:24:30 SQL〉select * from test;//按时间顺序为第四个操作
ID NAME
--- -----------
1 time
2 b
3 charge
10:25:30 SQL〉update test set name=‘goon’ where name=‘charge’;//按时间顺序为第五个操作
已更新1行
10:26:30 SQL〉select * from test;//按时间顺序为第六个操作
ID NAME
--- -----------
1 time
2 b
3 goon
会话2:
SQL〉set time on
10:20:10 SQL〉update test set name=‘charge’ where id=3;//按时间顺序为第一个操作
已更新1行
已提交
实验说明:
select操作(即读操作)开始执行时,它会以自己开始执行的时间SCN为准对它所要操作的表的所有数据内容进行一次一致性读模式的读取过程来回滚以获得select操作开始执行时的那一刻表的内容,接着再根据过滤条件(即where后的限制条件)过滤出select语句的结果,最后将这些结果显示在屏幕上。
DML操作(即写操作)开始执行时,它也会以自己开始执行的时间SCN为准对它所要操作的表的所有数据内容进行一次一致性读模式的读取过程来回滚以获得DML操作开始执行时的那一刻表的内容,接着再根据过滤条件(即where后的限制条件)过滤出DML操作的所要操作的那些数据行,最后DML操作根据这些数据行的地址以当前读模式找到在buffer cache上的相关数据行,对它们进行修改操作。
select操作(即读操作)和DML操作(即写操作)两个操作有一个共同点就是都有一个一致性读模式的读取过程,而DML操作(即写操作)还有一个当前读模式的修改过程。
回到本实验,假设一个DML操作的一致性读过程是以该操作所在的事务开始的时间为准回滚的,那么按时间顺序为第五个的操作(即update test set name=‘goon’ where name=‘charge’)的一致性读过程是以它所在的事务开始的时间,即按时间顺序为第二个的操作( update test set name=‘time’ where id=1)的/时间(10:22:22)为准进行回滚的,这样回滚后对按时间顺序为第五个的操作来说,它看到表test内容如下:
ID NAME
--- -----------
1 a
2 b
3 c
这样,它就发现表test的name字段不存在值为charge的,那 按时间顺序为第五个的操作的执行结果应该为未选定行才对,不是 已更新1行。而假设一个DML操作的一致性读过程是以自己开始执行的时间为准回滚的不是以该操作所在的事务开始的时间为准回滚的,就能说明本实验的结果了。具体过程如下:
按时间顺序为第五个的操作(即update test set name=‘goon’ where name=‘charge’)的一致性读过程是以自己开始执行的时间,即10:25:30为准进行回滚的,这样回滚后对按时间顺序为第五个的操作来说,它看到表test内容如下:
ID NAME
--- -----------
1 time
2 b
3 charge
这样,它就发现表test的name字段存在值为charge的,那 按时间顺序为第五个的操作根据该数据行的地址以 当前读模式找到在buffer cache上的相关数据行,对它进行了修改,执行结果故而为 已更新1行。注释:
假设还有个会话3在10:25:00时,update test set name=‘holy’ where id=2,但是之后一直不提交,这样的话,按时间顺序为第五个的操作执行一致性读过程后,看到的表test内容里id=2的那一行的name还是为b,不是holy,因为一致性读时,读取的是undo块中提交的记录,而不会读取未提交的记录的。
=======================================================================================================
原理版:
会话1:
SQL〉set time on
【
会话2:
SQL〉set time on
10:20:10 SQL〉update test set name=‘charge’ where id=3;//按时间顺序为第一个操作
已更新1行】
10:22:22 SQL〉update test set name=‘time’ where id=1;//按时间顺序为第二个操作
已更新1行
【
会话2:
10:23:25 SQL〉commit; //按时间顺序为第三个操作已提交
】
10:24:30 SQL〉select * from test;//按时间顺序为第四个操作
ID NAME
--- -----------
1 time
2 b
3 charge
10:25:30 SQL〉update test set name=‘goon’ where name=‘charge’;//按时间顺序为第五个操作
已更新1行
10:26:30 SQL〉select * from test;//按时间顺序为第六个操作
ID NAME
--- -----------
1 time
2 b
3 goon