崔华,网名 dbsnake
Oracle ACE Director,ACOUG 核心专家
编辑手记:感谢崔华授权我们独家转载其精品文章,也欢迎大家向“Oracle”社区投稿。
大家都知道的一个常识是 - Oracle 里未 commit 的数据除了当前 session 之外,其他 session 是看不到的。
我这里演示了一个有趣的例子,在这个例子里我们可以看到,Oracle里未成功 commit 的数据我们也可能能看到。
我同时启4个 session。
先在 session 1里创建一个表t1,插入一条数据但不 commit:
Session 1:
Connected to Oracle Database 11g
Enterprise Edition Release 11.2.0.1.0
Connected as scott
SQL> create table t1(id number, name varchar2(10));
Table created
SQL> insert into t1 values(1,’CUIHUA’);
1 row inserted
SQL> select * from t1;
ID NAME
———- ———-
1 CUIHUA
此时跳到 session 2,因session 1里刚插入的那条数据还未commit,所以这个时候 session 2是看不到这条数据的:
Session 2:
SQL> select * from t1;
ID NAME
———- ———-
接着我们跳到 session 3,把lgwr进程suspend住:
Session 3:
SQL> select spid from v$process where pname=’LGWR’;
SPID
————————
2316
SQL> oradebug setospid 2316
Oracle pid: 11, Windows thread id: 2316,
image: ORACLE.EXE (LGWR)
SQL> oradebug suspend
已处理的语句
现在我们回到 session 1,执行commit命令,因为 lgwr 进程已经被我们 suspend 住了,所以当前 session 1里要执行的 commit 操作一定会被hang住:
Session1:
SQL> commit;
……这里 hang 住了
Oracle 里 commit 操作的流程是这样的:
1、Oracle 先去改这个 transaction 所对应的 undo segment header 中 slot 的状态;
2、改完状态后再 flush log buffer;
现在我们把lgwr hold住了,所以上述步骤2 Oracle是没法做了,但步骤1还是可以做的。
而只要步骤1做完了,其他的 session 就能看到这个transaction所做的改变了(通过ITL中记录的 transaction id 去 check相应的 undo segment header 中 slot 的状态),也就是说对于其他 session 而言,这个 transaction 已经 commit 了,虽然这个 transaction 其实并没有成功commit。
好了,我们现在回到session 2,看一下我们现在能否看到刚才insert的那条记录:
Session 2:
SQL> select * from t1;
ID NAME
———- ———-
1 CUIHUA
从结果里可以看到,刚才看不到的那条记录现在我们已经能看到了,即 session 1对于 session2而言已经 commit 了,虽然 session1的 commit 操作其实并没有成功的做完。
现在我们跳到 session 4,执行shutdown abort:
Session 4:
SQL> shutdown abort
ORACLE 例程已经关闭。
然后我们再在 session 4中执行 startup,startup 后我们从 alert log 里可以很明显的看到
Oracle做了 instance recovery:
等待上述库成功startup后,我们再次回到session 1,看一下刚才我们已经commit的那条数据是否还在:
Session 1:
SQL> select * from t1;
ID NAME
———- ———-
从结果里可以看到,刚才我们 insert 且执行了 commit 操作的那条记录现在已经丢失了。
建议大家动手操作一下,以深入理解Oracle的事务隔离机制,事务恢复原理。
本文出自数据和云公众号,原文链接