我申请这个blog是为了督促自己,把自己平时的一些想法和思考结果保留下来。 本博客所有内容均为原创,如有转载请注明作者和出处

Oracle11新特性——撤销事务(二)

上一篇 / 下一篇  2007-12-18 00:00:00 / 个人分类:ORACLE

打算写一系列的文章介绍11g的新特性和变化。

Oracle11g提供了撤销事务的功能,可以撤销一个已经提交的事务。

这一篇介绍撤销级联事务。

Oracle11新特性——撤销事务(一):http://yangtingkun.itpub.net/post/468/419695


:l$M2^.Z,p0

上面一篇简单介绍了如何撤销一个事务,那个例子中,被撤销事务和其他事务没有关联。如果撤销一个事务的时候发现被撤销事务和其他事务级联,那么会有多种情况。

SQL> CONN YANGTK/yangtk@172.0.2.61/test11g.netdb已连接。ITPUB个人空间8G5q+e;z(z u8D8vpd4m
SQL> CREATE TABLE T_FLASH_TRANS (ID NUMBER, NAME VARCHAR2(30));

表已创建。

SQL> INSERT INTO T_FLASH_TRANS VALUES (1, 'A');

已创建 1 行。

SQL> INSERT INTO T_FLASH_TRANS VALUES (2, 'B');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> UPDATE T_FLASH_TRANS SET NAME = NAME || '1';

已更新2行。

SQL> INSERT INTO T_FLASH_TRANS VALUES (3, 'C');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> UPDATE T_FLASH_TRANS SET NAME = NAME || '2' WHERE ID = 1;

已更新 1 行。

SQL> INSERT INTO T_FLASH_TRANS VALUES (4, 'D');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> CONN SYS/test@172.0.2.61/TEST11G.NETDB AS SYSDBA已连接。
M&Z _@Y_%wil!Z0SQL> SELECT XID, OPERATION, UNDO_SQL
Q+G {"o"p'p+bp0 2 FROM FLASHBACK_TRANSACTION_QUERYITPUB个人空间n'oDo+p
3 WHERE TABLE_NAME = 'T_FLASH_TRANS';

XID OPERATION UNDO_SQLITPUB个人空间1u%X s'bH X"w|
---------------- ---------- ------------------------------------------------------------------------
-D&W Q1KANDK00004001A00000344 INSERT delete from "YANGTK"."T_FLASH_TRANS" where ROWID = 'AAARskAAFAAACY3AAC';ITPUB个人空间 _!y U*|h%N Q7HF
0004001A00000344 UPDATE update "YANGTK"."T_FLASH_TRANS" set "NAME" = 'B' where ROWID = 'AAARskAAITPUB个人空间-K `0lOI
0004001A00000344 UPDATE update "YANGTK"."T_FLASH_TRANS" set "NAME" = 'A' where ROWID = 'AAARskAA
S{o z/j0k00006002F00000345 INSERT delete from "YANGTK"."T_FLASH_TRANS" where ROWID = 'AAARskAAFAAACY3AAD';ITPUB个人空间b+m+LJI&pk/h
0006002F00000345 UPDATE update "YANGTK"."T_FLASH_TRANS" set "NAME" = 'A1' where ROWID = 'AAARskA
7p2R8wJ'?f4z%x;vP0000A005000000343 INSERT delete from "YANGTK"."T_FLASH_TRANS" where ROWID = 'AAARskAAFAAACY3AAB';
.DRtjsq0000A005000000343 INSERT delete from "YANGTK"."T_FLASH_TRANS" where ROWID = 'AAARskAAFAAACY3AAA';

已选择7行。

下面对第一个更新进行撤销:

SQL> DECLARE
J!IPC"w/{4j0 2 V_XID XID_ARRAY;ITPUB个人空间k4p#JM'Dvq
3 BEGINITPUB个人空间[kxv~6E4w
4 V_XID := SYS.XID_ARRAY('0004001A00000344');
?+n+DK6n nQP0 5 DBMS_FLASHBACK.TRANSACTION_BACKOUT(1, V_XID);ITPUB个人空间 Xj)o&a&\/b!E,i
6 END;ITPUB个人空间!h O+U-L0Gg h9v e f
7 /ITPUB个人空间;| NR)Xf
DECLARE
{t S*@ R'c;|Tg0*
1 行出现错误:ITPUB个人空间Iv[ ] m-~
ORA-55504: NOCASCADE
模式下的事务处理冲突
ITPUB个人空间V(U{dA9|N5B sc
ORA-06512:
"SYS.DBMS_FLASHBACK", line 37
/A*`(Wsr0ORA-06512:
"SYS.DBMS_FLASHBACK", line 70
ls9l/W#j0ORA-06512:
line 5

撤销出错,这是由于要撤销第二个事务,这个事务对ID1的记录进行了更新,但是在随后的事务中又对这条记录进行了修改。也就是说这个事务是后面事务的基础,这时没有办法仅仅撤销前面的事务而不影响后面的事务。

对于这种情况,Oracle有三种不同的解决方法,其中最好理解的方法是CASCADE方式:

SQL> DECLAREITPUB个人空间Npkd0r
2 V_XID XID_ARRAY;
4rL U;l*]M0 3 BEGINITPUB个人空间??J#n\;aU Z
4 V_XID := SYS.XID_ARRAY('0004001A00000344');ITPUB个人空间,H:Dw5`d,i f
5 DBMS_FLASHBACK.TRANSACTION_BACKOUT(1, V_XID, DBMS_FLASHBACK.CASCADE);
B h&c!E,nX0r0 6 END;
"W],~o#vuI~ z z0 7 /

PL/SQL 过程已成功完成。

SQL> SELECT * FROM YANGTK.T_FLASH_TRANS;

ID NAMEITPUB个人空间:V6q7h$|B4r
---------- ------------------------------ITPUB个人空间QjM9W,YR8r}#s
1 AITPUB个人空间3_3Y_[0O!j1U%j
2 B

使用CASCADE方式,会根据事务提交的相反顺序,依次撤销所有关联的事务。

在这个例子中,Oracle不但撤销了第一个UPDATE事务,而且撤销了随后的UPDATEINSERT事务。

下面看第二种方式,NONCONFLICT_ONLY。在采用这种方式之前,先要说明一下,TRANSACTION_BACKOUT过程是事务性的,也就是说,如果发现撤销事务后,得到的不是预期的结果,还可以通过ROLLBACK来回滚事务撤销操作本身:

SQL> ROLLBACK;

回退已完成。

SQL> SELECT * FROM YANGTK.T_FLASH_TRANS;

ID NAME
S8pX5U#J'E0---------- ------------------------------
3?h6nWrs F0 1 A12
}NO].Q0 2 B1ITPUB个人空间g?grM;lK0q3kU(}
3 C
[URPCb%o0 4 D

下面采用NONCONFLICT_ONLY方式进行事务撤销:

SQL> DECLARE
dDad$Mk0 2 V_XID XID_ARRAY;
Z8Y!\-kG&J;s?Z0 3 BEGIN
;k.s+q#U ie6o0 4 V_XID := SYS.XID_ARRAY('0004001A00000344');
I_bDnK%c)lg0 5 DBMS_FLASHBACK.TRANSACTION_BACKOUT(1, V_XID, DBMS_FLASHBACK.NONCONFLICT_ONLY);ITPUB个人空间Zet7}@3b
6 END;ITPUB个人空间~W$z in*~O@~r,T
7 /

PL/SQL 过程已成功完成。

SQL> SELECT * FROM YANGTK.T_FLASH_TRANS;

ID NAMEITPUB个人空间J.iXw"b)B^B
---------- ------------------------------ITPUB个人空间"o!J:B6C8E:C%iUS
1 A12ITPUB个人空间G3OQo6SzO
2 BITPUB个人空间4x3]E4op;u b)D
4 D

对于NONCONFLICT_ONLY方式,Oracle会回滚指定事务中没有被关联的部分。比如这个例子中,UPDATE语句被后面的事务关联,但是INSERT语句并没有被关联。因此,撤销了事务中的INSERT语句,对于UPDATE语句,只有关联的那条数据没有被撤销,而没有被关联的数据则被撤销成功。这种方式可以保证数据库的一致性,但是会损失事务的完整性。

Oracle文档上还描述了一种方式NOCASCADE_FORCE

SQL> ROLLBACK;

回退已完成。

SQL> SELECT * FROM YANGTK.T_FLASH_TRANS;

ID NAMEITPUB个人空间q7xhTjc(p
---------- ------------------------------ITPUB个人空间f7w"k-k,\Y6D j:l
1 A12ITPUB个人空间CfQ"A k?zt;F
2 B1ITPUB个人空间I gJ&{'b'H
3 C
9b wr(h8mR]0 4 D

SQL> DECLAREITPUB个人空间a)B&Qc2Ws
2 V_XID XID_ARRAY;ITPUB个人空间 _U:{!iYRAy x
3 BEGINITPUB个人空间0C3t6U+n:nb
4 V_XID := SYS.XID_ARRAY('0004001A00000344');ITPUB个人空间#I]$],v8@h.mS%M0UE
5 DBMS_FLASHBACK.TRANSACTION_BACKOUT(1, V_XID, DBMS_FLASHBACK.NOCASCADE_FORCE);
#h8^+i1a7s?*p3mv0 6 END;ITPUB个人空间 ezv/NpT@d
7 /

PL/SQL 过程已成功完成。

SQL> SELECT * FROM YANGTK.T_FLASH_TRANS;

ID NAMEITPUB个人空间3N$G E'Z?$m#g
---------- ------------------------------
DF4RH$v*Jw0 1 A12ITPUB个人空间'~/qxw-KWhc
2 BITPUB个人空间:F1OCM$o6q8G[Ap
4 D

根据文档上的描述,个人感觉采用这种方式的撤销后,ID1的记录NAME应该为A而不是A12,现在的这种结果与NONCONFLICT_ONLY方式没有差别,怀疑目前的结果是个bug。不过实际如何只能等Oracle推出补丁或者声明bug才能了解。


TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar