重启动

来源:互联网 发布:淘宝图片不清楚 编辑:程序博客网 时间:2024/05/22 14:21

 

重启动发生的原因

where条件读取时采用一致读和更新时采取当前读版本不一致造成
Oracle在执行DML语句时,会用到两种不同的方式去读取数据块:
1. 一致读:在“找到”需要修改的数据行时,会采用 consistent read
2. 当前读:在“获取”数据块来实际更新数据行时,会采用 current read

如更新这个语句update test set x=1 where y=1;
首先Oracle会利用一致读找到所有y=1的数据行,因此就算读取期间有别的会话修改了某一行的y值(如从y=1变为 y=2),
Oracle也会利用undo数据将该行的y列恢复到读取的那个时刻的值(即y=1),所以这一行还是会被读取。然后,当要实际更新这一行的时候,
Oracle会利用当前读去获取数据块的最新版本,由于被提交过了,所以读到的y值是2,与之前一致读中的y=1不符。
所以Oracle就知道了需要 “重启动”这个update操作。

来演示一下写一致性的查询重启动。

session 1:
------------
C:\Documents and Settings\Administrator>sqlplus /nolog

SQL*Plus: Release 9.2.0.8.0 - Production on 星期二 12月 25 21:19:28 2007

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

SQL> connhujinpei/passw0rd@icmnlsdb
已连接。
SQL> create table t ( x int , y int);

表已创建。

SQL> insert into t values (1 ,1);

已创建 1 行。

SQL> commit;

提交完成。

创建一个trigger来,观察重启动
SQL> 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||', old.y = '||:old.y);
  5     dbms_output.put_line('new.x = '||:new.x||', new.y = ' || :new.y);
  6  end;
  7  /

触发器已创建

SQL> set serveroutput on
SQL> update t set x=x+1;
old.x = 1, old.y = 1
new.x = 2, new.y = 1

已更新 1 行。

SQL> update t set x=x+1;
old.x = 2, old.y = 1
new.x = 3, new.y = 1

已更新 1 行。

SQL> update t set x=x+1;
old.x = 3, old.y = 1
new.x = 4, new.y = 1

已更新 1 行。

这个时候我们切换到session 2:
C:\Documents and Settings\Administrator>sqlplus /nolog

SQL*Plus: Release 9.2.0.8.0 - Production on 星期二 12月 25 21:19:54 2007

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

SQL> connhujinpei/passw0rd@icmnlsdb
已连接。
SQL> set serveroutput on
SQL> update t set x=x+10 where x>0;   此时会阻塞,需要提交会话1才能看到结果
old.x = 1, old.y = 1
new.x = 11, new.y = 1
old.x = 4, old.y = 1
new.x = 14, new.y = 1

已更新 1 行。

我们发现trigger被触发了两次

分析:

其实session 2的更新经历了consistent read和current read两个过程。由于session 1的transaction因为没有提交而阻塞了session 2的更新,session 2开始执行update的时候就被session 1阻塞了,但是session 2会在where条件中一致读,这个时候x的value是1,所以new.x=11。而当session 1提交后,session2也可以继续更新了,会做一次当前读,然后比较两次读的值是否一致,如果不一致,oracle会重新启动查询更新。
而如果session 1没有提交而是回滚了呢。那么trigger就被触发一次。

0 0
原创粉丝点击