到目前为止,介绍的所有功能均不会直接将数据恢复为“以前”的样子。闪回查询只是查看,闪回数据归档只是延伸了闪回查询的时间窗口,闪回事务查询虽然提供了撤销SQL,但是否执行及如何执行还需要管理员进一步手动操作。

若是管理员决定撤销某个或某些事务,Oracle提供一个专门用来撤销事务的工具——闪回事务。

闪回事务又名撤销事务(Backout Transaction),能够撤销一个或多个事务的修改,其功能由一个名为DBMS_FLASHBACK.TRANSACTION_BACKOUT的存储过程实现。该存储过程的工作原理是自动分析重做日志,挖掘出变更前的值用以构建撤销SQL(Undo SQL),然后执行撤销SQL最后达到撤销事务的目的。为了该功能可以正常使用,至少需要事先启用主键补充日志。另外,为了能够跟踪外键依赖还需要启用外键补充日志。

在继续讨论此功能前,首先应了解一个概念:事务的依赖性。比如,两个事务TX1和TX2,若符合以下3个条件的任意一个就可以认为TX2依赖TX1:

(1)WAW依赖(Write After Write),即在TX1修改了表的某行之后,TX2又修改了同一行。

(2)主键依赖,即在一张拥有主键的表中TX1首先删除了一行,之后TX2又插入了具有相同主键值的另一行。

(3)外建依赖,即由于TX1的修改(insert或update)而产生了新的可被外键参考的字段值,之后TX2修改(insert或update)外键字段时利用了TX1所产生的字段值。

了解事务依赖性有助于解决在撤销事务时遇到的矛盾,以主键依赖为例,试想若直接将事务TX1撤销并且不理会事务TX2,岂不是会出现主键值重复的行!

TRANSACTION_BACKOUT存储过程的OPTIONS参数就是为了解决事务依赖性问题而存在的,在该参数上管理员可以使用4种撤销事务的方案,假设被撤销的事务是TX1,若其具有依赖事务,则称为TX2:

(1)NOCASCADE,TX1不可以被任何其他事务依赖(即TX2不存在),否则撤销操作报错。

(2)CASCADE,将TX1连同TX2一起撤销。

(3)NOCASCADE_FORCE,忽略TX2,直接执行TX1的撤销SQL将TX1撤销,如果没有约束上的冲突,操作将成功,否则约束报错导致撤销操作失败。

(4)NONCONFILICT_ONLY,在不影响TX2的前提下,撤销TX1的修改。与NOCASCADE_FORCE的不同点在于会首先过滤一下TX1的撤销SQL,确保它们不会作用在TX2修改的行上。

接下来以WAW依赖为例详细说明,比如有一张表的原有数据如下所示,只有3行且没有约束:

ID
----------
         1
         2
         3

接下来先后发起事务TX1和TX2仅修改该表。在事务TX1(更新了3行)执行后其数据变更为:

ID
----------
        11
        22
        33

之后,在事务TX2(更新了两行,第一行没有修改)执行后其数据变更为:

ID
----------
        11
       222
       333

此例为典型的WAW依赖,TX2依赖TX1。

现在计划将事务TX1撤销,那么使用不同的OPTIONS将产生不同的结果。

若采用NOCASCADE结果是抛出错误“ORA-55504: Transaction conflicts in NOCASCADE mode”,表内容依然是:

ID
----------
        11
       222
       333

若采用CASCADE,表的内容恢复到TX2和TX1均未执行的状态:

ID
----------
         1
         2
         3

若采用NOCASCADE_FORCE,TX2的结果不受影响,但被TX1修改的第一行回滚了,闪回事务没有尊重TX1的事务原子性。表的内容变为:

ID
----------
         1
       222
       333

也许读者会感到奇怪,根据NOCASCADE_FORCE的定义,会在所有行上执行撤销SQL,那为什么第2和第3行的内容没有回到TX1执行之前呢?原因是此例中撤销SQL的where语句中还包含ID字段的值,这是启用了主键补充日志的结果:

update <表名> set "ID" = '1' where "ID" = '11' and ROWID = <第1行ROWID>;
update <表名> set "ID" = '2' where "ID" = '22' and ROWID = <第2行ROWID>;
update <表名> set "ID" = '3' where "ID" = '33' and ROWID = <第3行ROWID>;

没记错的话第2和第3行的ID字段已经被TX2分别修改为222和333了,所以虽然执行了3条撤销SQL,但只有第1行得到了修改。

若采用NONCONFILICT_ONLY,在此例中将产生与NOCASCADE_FORCE一样的结果:

ID
----------
         1
       222
       333

读者需要明白本情况中的撤销SQL应该只有一条:

update <表名> set "ID" = '1' where "ID" = '11' and ROWID = <第1行ROWID>;

虽然最后的结果是相同的,但是与NOCASCADE_FORCE所做的尝试是不同的,和TX2有关的对第2行、第3行的更改命令首先被过滤了。试想若在事务TX2之后还有一个事务TX3又将第3行的ID字段改回33,再使用NOCASCADE_FORCE和NONCONFILICT_ ONLY将TX1闪回,结果将会怎样。

使用DBMS_FLASHBACK.BACKOUT_TRANSACTION的步骤如下:

(1)将需要撤销的事务的事务号或事务名载入对应的VARRAY集合变量。

(2)以NOCASCADE方式调用BACKOUT_TRANSACTION。如果报错,再从另外3种方式中选择一个调用BACKOUT_TRANSACTION。

(3)查看闪回事务操作的报告。

(4)最后决定提交或回滚。

下面是一个展示闪回事务战斗力的例子,作为本节的结尾。

首先确认一下201号员工的薪水是13000美元:

SQL> select salary from hr.employees where employee_id=201;

SALARY
------
 13000

然后,将全体员工的工资涨500 %,这是一次人为错误,201号员工的收入变为78000美元了:

SQL> update hr.employees set salary=salary*5;

107 rows updated.

SQL> commit;

Commit complete.

紧接着,人事管理应用发出一个正常的操作将201号员工的工资上浮10 %,这里笔者用SQL*Plus模拟HR应用:

SQL> update hr.employees set salary=salary*1.1 where employee_id=201;

1 row updated.

SQL> commit;

Commit complete.

显然HR应用的本意是让201号员工获得13000美元的110%,即14300美元月薪,但是经过前一次错误update的修改,如今该员工的薪水是85800美元:

SQL> select salary from hr.employees where employee_id=201;

SALARY
----------
     71500

不久之后,工作人员发现所有员工的薪水高得反常,管理员受理之后通过闪回事务查询查询发现最近(15分钟之内)在hr.employees表上的事务有两个:

SQL> select distinct xid,commit_scn
   2 from flashback_transaction_query
   3 where table_owner='HR' and
   4 table_name='EMPLOYEES' and
   5 commit_timestamp > systimestamp - interval '15' minute
   6 order by commit_scn;

XID              COMMIT_SCN
---------------- ----------
0A00160094020000    1277129
0900070068030000    1277301

然后再利用闪回事务查询观察FLASHBACK_TRANSACTION_QUERY.UNDO_SQL字段,了解到COMMIT_SCN号是1277129、事务号为0A00160094020000的事务很不正常,不但更新了所有员工的SALARY,而且金额太大(因为撤销SQL中的SALARY很低,而当前SALARY很高):

SQL> select undo_sql from flashback_transaction_query
  2  where commit_scn='1277129';

UNDO_SQL
----------------------------------------------------------------------------
update "HR"."EMPLOYEES" set "SALARY" = '3000' where ROWID = 'AAAR5pAAFAAAADPABh';
update "HR"."EMPLOYEES" set "SALARY" = '3100' where ROWID = 'AAAR5pAAFAAAADPABg';
update "HR"."EMPLOYEES" set "SALARY" = '2800' where ROWID = 'AAAR5pAAFAAAADPABf';
update "HR"."EMPLOYEES" set "SALARY" = '3200' where ROWID = 'AAAR5pAAFAAAADPABe';
update "HR"."EMPLOYEES" set "SALARY" = '3900' where ROWID = 'AAAR5pAAFAAAADPABd';
update "HR"."EMPLOYEES" set "SALARY" = '4000' where ROWID = 'AAAR5pAAFAAAADPABc';
update "HR"."EMPLOYEES" set "SALARY" = '2500' where ROWID = 'AAAR5pAAFAAAADPABb';

...省略100行

注意撤销SQL中赋予SALARY字段的值正是事务0A00160094020000执行前的值。现决定用TRANSACTION_BACKOUT闪回该事务,使SALARY恢复正常值:

SQL> declare
  2   xids sys.xid_array;
  3  begin
  4   xids := sys.xid_array('0A00160094020000');
  5   dbms_flashback.transaction_backout(1,xids,options=>dbms_flashback.nocascade);
  6  end;
  7  /

第5行中存储过程的第二个参数是一个容纳事务号的VARRAY集合变量,第一个参数表示VARRAY内事务号的数量,本例中只有一个事务需要撤销,所以等于1。

因为WAW依赖性,这样执行会失败:

declare
*
ERROR at line 1:
ORA-55504: Transaction conflicts in NOCASCADE mode
ORA-06512: at "SYS.DBMS_FLASHBACK", line 37
ORA-06512: at "SYS.DBMS_FLASHBACK", line 70
ORA-06512: at line 5

现在最符合逻辑的做法是使用casecade方式将两个事务全部撤销,修改options参数后重新执行:

SQL> declare
  2   xids sys.xid_array;
  3  begin
  4   xids := sys.xid_array('0A00160094020000');
  5   dbms_flashback.transaction_backout(1,xids,options=>dbms_flashback.cascade);
  6  end;
  7  /

PL/SQL procedure successfully completed.

待执行完毕后查看闪回事务的报告:

SQL> select xid,dependent_xid,backout_mode from dba_flashback_txn_state;

XID              DEPENDENT_XID    BACKOUT_MODE
---------------- ---------------- ----------------
0900070068030000                  CASCADE
0A00160094020000 0900070068030000 CASCADE

发现事务0900070068030000也被撤销了。

查看201号员工的薪水:

SQL> select salary from hr.employees where employee_id=201;

SALARY
----------
     13000

果然回到了最初的13000美元。现在所有员工的薪水应该都恢复正常了。

DBMS_FLASHBACK.TRANSACTION_BACKOUT是用一个新的事务执行撤销SQL的,现在应执行commit或rollback命令确认或取消闪回事务的结果,这里使用commit:

SQL> commit;

Commit complete.

闪回事务至此结束。

闪回事务(Flashback Transaction)的更多相关文章

  1. Oracle闪回技术(Flashback)

    闪回技术有闪回表.闪回删除.闪回查询.闪回事务查询.闪回事务.闪回数据库.闪回数据归档.其中,闪回查询.闪回事务查询用来“观察”过去:闪回数据归档并不是一个独立的功能,其功能是扩展闪回查询的时间窗口: ...

  2. Oracle 闪回特性(FLASHBACK DATABASE)

    --===================================== -- Oracle 闪回特性(FLASHBACK DATABASE) --======================= ...

  3. SQL Fundamentals: 表的创建和管理(表的基本操作,闪回技术flashback,表结构修改)

    SQL Fundamentals || Oracle SQL语言 1.表的基本操作 (CREATE TABLE, DROP TABLE,TRUNCATE TABLE, RENAME tablename ...

  4. oracle闪回(flashback)的部分实用操作(彻底删除的除外)

    一.数据delete并且commit提交之后的闪回 (一):根据时间来恢复:1.查询数据库当前时间(目的是为了检查数据库时间是否与你电脑时间相近,避免时间不同而将数据恢复到错误时间点)select  ...

  5. 闪回工具flashback

    Ⅰ.背景 早先操作数据误操作后,我们一般通过全量备份+binlog的方式来实现恢复(前滚) 有时只想撤销一个几分钟前的操作,采用这种方式就会显得很笨重 大家都知道Oracle有个叫做flashback ...

  6. Oracle 的闪回技术 --flashback

    SQL Fundamentals: 表的创建和管理 如何开启数据库闪回? SQL> shutdown immediate; ORA-01109: database not open Databa ...

  7. 闪回之 Flashback Query (dml表、过程、函数、包等)、Flashback version Query

    Flashback Query 背景:Flashback 是 ORACLE 自 9i 就开始提供的一项特性,在 9i 中利用oracle 查询多版本一致的特点,实现从回滚段中读取表一定时间内操作过的数 ...

  8. PLSQL_闪回操作3_Fashback Transaction Query

    2014-12-09 Created By BaoXinjian

  9. PLSQL_闪回删除FlashBack Delete表误删除如何进行恢复(案例)

    2014-07-02 Created By BaoXinjian

随机推荐

  1. javax.Servlet的包中,属于类的是。(选择1项)

    javax.Servlet的包中,属于类的是.(选择1项) A.Servlet B.GenericServlet C.ServletRequest D.ServletContext 解答:B Serv ...

  2. Unity5 AssetBundle打包加载及服务器加载

    Assetbundle为资源包不是资源 打包1:通过脚本指定打包 AssetBundleBuild ab = new AssetBundleBuild                         ...

  3. 【BZOJ】1625: [Usaco2007 Dec]宝石手镯(01背包)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1625 太水了. #include <cstdio> #include <cstri ...

  4. freemarker1 一些内建函数和用法

    ${"   green mouse"?cap_first} -->   Green mouse  //字符串中的第一个单词的首字母大写 ${"ABCDF" ...

  5. VS2008 对话框编辑器“即时预览”

    之前在VS2008中利用资源编辑器修改完对话框资源后,总是重新编译一下,然后Ctrl+F5运行来预览修改的效果,不断修改,不断编译,导致很费时,效率低下. 今天,发现了一个很好用的功能“Test Di ...

  6. Matplotlib植入PyQt5 + QT5的UI呈现

    实现matplotlib图形通过PyQt5+Qt5在GUI中呈现步骤: 第一步,通过matplotlib.backends.backend_qt5agg类来连接PyQt5: import matplo ...

  7. 系统管理模块_岗位管理_实现CRUD功能的具体步骤并设计Role实体

    系统管理模块_岗位管理_实现CRUD功能的具体步骤并设计Role实体 1,设计实体/表 设计实体 --> JavaBean --> hbm.xml --> 建表 设计Role实体 p ...

  8. ItcastOA_整体说明_准备环境

    1. 整体说明 1.1. 项目说明 1.1.1. OA概述 OA是Office Automation的缩写,本意为利用技术的手段提高办公的效率,进而实现办公的自动化处理.实现信息化.无纸化办公,可方便 ...

  9. UE打包32位程序遇到Win32 is not a supported platform for MindWaveEditor. Valid platforms are Win64.

    1>------ 已启动全部重新生成: 项目: MindWave, 配置: Development_Editor Win32 ------1> Win32 is not a support ...

  10. java基础---->hashSet的简单分析(一)

    对于HashSet而言,它是基于HashMap实现的,底层采用HashMap来保存元素的.今天我们就简单的分析一下它的实现.人生,总会有不期而遇的温暖,和生生不息的希望. HashSet的简单分析 一 ...