Oracle在执行DML语句时,会用到两种不同的方式去读取数据块:
1. 一致读:在“找到”需要修改的数据行时,会采用 consistent read
2. 当前读:在“获取”数据块来实际更新数据行时,会采用 current read
session 1
YXYUP@yxyup>create table t ( x int );
Table created.
YXYUP@yxyup>insert into t values (1);
1 row created.
YXYUP@yxyup>commit;
Commit complete.
YXYUP@yxyup>create or replace trigger t_buffer
2 before update on t for each row
3 begin
4 dbms_output.put_line('old.x = '||: old.x||');
5 dbms_output.put_line('new.x = '||:new.x||');
6 end;
7 /
YXYUP@yxyup>set serveroutput on
YXYUP@yxyup>update t set x=x+1;
old.x = 1
new.x = 2
1 row updated.
YXYUP@yxyup>update t set x=x+1;
old.x = 2
new.x = 3
1 row updated.
到 session 2
YXYUP@yxyup>set serveroutput on
YXYUP@yxyup>update t set x=x+10 ;
---这时是被阻塞的,因为 session 1还没有commit;
回到 session 1
YXYUP@yxyup>commit;
Commit complete.
再回到session 2
YXYUP@yxyup>update t set x=x+10 ;
old.x = 1
new.x = 11
old.x = 3
new.x = 13
1 row updated.
为什么 trigger被触发两次呢,这就是 查询重启动 导致的.
因为session 2 首先根据session 1中第一次提交后的SCN,从UNDO中查找到前映象数据 x=1,然后更新,这时x=11。这个过程也就是一致读。
而当session 1提交后再根据当前提交后的SCN,在当前数据块中找到x=3,然后再更新 x=13 ,这个过程就是当读前。
以上这个过程就是查询重启动。