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%Xs'bHX"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{oz/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-L0Ggh9ve 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
撤销出错,这是由于要撤销第二个事务,这个事务对ID为1的记录进行了更新,但是在随后的事务中又对这条记录进行了修改。也就是说这个事务是后面事务的基础,这时没有办法仅仅撤销前面的事务而不影响后面的事务。
对于这种情况,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事务,而且撤销了随后的UPDATE和INSERT事务。
下面看第二种方式,NONCONFLICT_ONLY。在采用这种方式之前,先要说明一下,TRANSACTION_BACKOUT过程是事务性的,也就是说,如果发现撤销事务后,得到的不是预期的结果,还可以通过ROLLBACK来回滚事务撤销操作本身:
SQL> ROLLBACK;
回退已完成。
SQL> SELECT * FROM YANGTK.T_FLASH_TRANS;
ID NAME
S8pX5U#J'E0---------- ------------------------------
3?h6nWrsF0 1 A12
}NO].Q0 2 B1ITPUB个人空间g?grM;lK0q3kU(}
3 C
[URPCb%o0 4 D
下面采用NONCONFLICT_ONLY方式进行事务撤销:
SQL> DECLARE
d Dad$Mk0 2 V_XID XID_ARRAY;
Z8Y!\-kG&J;s?Z0 3 BEGIN
;k.s+q#Ui e6o0 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;ub)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"Ak?zt;F
2 B1ITPUB个人空间I
gJ&{'b'H
3 C
9bwr(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
根据文档上的描述,个人感觉采用这种方式的撤销后,ID为1的记录NAME应该为A而不是A12,现在的这种结果与NONCONFLICT_ONLY方式没有差别,怀疑目前的结果是个bug。不过实际如何只能等Oracle推出补丁或者声明bug才能了解。
导入论坛 引用链接 收藏 分享给好友 推荐到圈子 管理 举报
TAG: