验证DDL隐式提交
今天复习了下DDL的隐式提交,在执行DDL语句的时候,ORACLE为了保证事物的一致性,会对当前SESSION未提交的事务隐式提交,以保证DDL语句失败时的回滚位置,以下是DDL操作的伪代码。
从DDL的伪代码可以看到,在执行DDL操作时,首先会执行一个COMMIT操作,提交当前SESSION未提交的事务,然后才会处理DDL语句(DDL操作一般都是修改数据字典的DML操作),如果DDL语句正确执行,则提交,如果DDL语句执行失败,则回滚到第一个COMMIT的时间点,可见第一个COMMIT是为ORACLE提供的DDL失败时的回滚位置,也是为了不影响DDL之前的操作,可以通过以下两个实验来验证DDL操作的隐式提交。
实验一:DDL语句失败
实验表信息如下:
SESSION 1>select * from t_stream; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001
打开2个SQLPLUS窗口,SESSION1和SESSION2,SESSION1执行DML操作后,不提交。
SESSION 1>insert into t_stream values (5,'05','05-01-0001-000001'); 1 row created.
此时,由于SESSION1未提交,SESSION2查询不到这条记录。
SESSION 2>select * from t_stream; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001
SESSION1执行DDL操作,建立一张已存在的表。
SQL> create table t_dbdream as select * from t_test; create table t_dbdream as select * from t_test * ERROR at line 1: ORA-00955: name is already used by an existing object
虽然DDL操作失败,但是在执行DDL语句之前的COMMIT已经执行(DDL语法要正确,否则不会执行隐式提交),此时SESSION2可以查看到SESSION1之前插入的记录。
SESSION 2>select * from t_stream; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001 5 05 05-01-0001-000001
通过10046追踪日志中相关的信息。
insert into t_stream values (5,'05','05-01-0001-000001') END OF STMT PARSE #1:c=0,e=131,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1315862570391933 BINDS #1: EXEC #1:c=2000,e=2056,p=0,cr=1,cu=4,mis=0,r=1,dep=0,og=1,tim=1315862570394101 WAIT #1: nam='SQL*Net message to client' ela= 2 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1315862570394208 *** 2012-09-12 17:48:02.099 WAIT #1: nam='SQL*Net message from client' ela= 9780944 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1315862580175186 XCTEND rlbk=0, rd_only=0
可以看到在INSERT语句之后,DDL操作触发了COMMIT操作,INSERT操作已经被提交。
实验一:DDL语句成功
还是之前的实验表T_STREAM
SESSION 1>select * from t_stream; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001
同样是SESSION1和SESSION2操作,唯一区别是SESSION1运行的DDL语句成功运行。
SESSION 1>insert into t_stream values (5,'05','05-01-0001-000001'); 1 row created.
此时,由于SESSION1未提交,SESSION2查询不到这条记录。
SESSION 2>select * from t_stream; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001
SESSION1执行DDL操作,建立一张新表。
SESSION 1>create table t_dbdreams as select * from t_test; Table created.
由于触发隐式提交,此时SESSION2可以查看到SESSION1之前插入的记录。
SESSION 2>select * from t_stream; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001 5 05 05-01-0001-000001
10046追踪日志相关信息如下:
insert into t_stream values (5,'05','05-01-0001-000001') END OF STMT PARSE #1:c=0,e=262,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1315856684369288 BINDS #1: EXEC #1:c=1999,e=1523,p=0,cr=1,cu=4,mis=0,r=1,dep=0,og=1,tim=1315856684370856 WAIT #1: nam='SQL*Net message to client' ela= 2 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1315856684370932 *** 2012-09-12 16:07:45.814 WAIT #1: nam='SQL*Net message from client' ela= 20525585 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1315856704896560 XCTEND rlbk=0, rd_only=0
INSERT语句之后,DDL操作触发了COMMIT操作,INSERT操作已经被提交。
update tsq$ set blocks=:3,maxblocks=:4,grantor#=:5,priv1=:6,priv2=:7,priv3=:8 where ts#=:1 and user#=:2 insert into obj$(owner#,name,namespace,obj#,type#,ctime,mtime,stime,status, remoteowner,linkname,subname,dataobj#,flags,oid$,spare1,spare2)values(:1,:2,:3, :4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16, :17) insert into seg$ (file#,block#,type#,ts#,blocks,extents,minexts,maxexts,extsize, extpct,user#,iniexts,lists,groups,cachehint,bitmapranges,hwmincr, spare1, scanhint) values (:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,0,:16, DECODE(:17,0,NULL,:17),:18) insert into tab$(obj#,ts#,file#,block#,bobj#,tab#,intcols,kernelcols,clucols, audit$,flags,pctfree$,pctused$,initrans,maxtrans,rowcnt,blkcnt,empcnt,avgspc, chncnt,avgrln,analyzetime,samplesize,cols,property,degree,instances,dataobj#, avgspc_flb,flbcnt,trigflag,spare1,spare6)values(:1,:2,:3,:4,decode(:5,0,null, :5),decode(:6,0,null,:6),:7,:8,decode(:9,0,null,:9),:10,:11,:12,:13,:14,:15, :16,:17,:18,:19,:20,:21,:22,:23,:24,:25,decode(:26,1,null,:26),decode(:27,1, null,:27),:28,:29,:30,:31,:32,:33) insert into col$(obj#,name,intcol#,segcol#,type#,length,precision#,scale,null$, offset,fixedstorage,segcollength,deflength,default$,col#,property,charsetid, charsetform,spare1,spare2,spare3)values(:1,:2,:3,:4,:5,:6,decode (:5,182/*DTYIYM*/,:7,183/*DTYIDS*/,:7,decode(:7,0,null,:7)),decode(:5,2,decode (:8,-127/*MAXSB1MINAL*/,null,:8),178,:8,179,:8,180,:8,181,:8,182,:8,183,:8,231, :8,null),:9,0,:10,:11,decode(:12,0,null,:12),:13,:14,:15,:16,:17,:18,:19,:20) END OF STMT EXEC #3:c=1000,e=852,p=0,cr=2,cu=7,mis=0,r=1,dep=1,og=4,tim=1315856705104698 XCTEND rlbk=0, rd_only=0
在DDL语句触发的INSERT和UPDATE相关数据字典后,也执行了COMMIT,也就是上文DDL伪代码中的第二个COMMIT。