在工作当中时常会出现这么一种情况:修改错了数据,或者误删了数据,或者插入了一些不应该插入的数据。这种情况不是实例崩溃,也没有出现介质损坏,只是正常工作中出现了操作事务,并没有使得数据库处于不一致的状态。这此时是事务故障。为了处理这些故障,ORACLE提供了闪回技术。除了闪回删除是通过recyclebin来恢复之外,其他的都利用了undo撤销段来进行恢复。为了维护一致性,数据库在读出需要修改的数据块到高速缓冲区的时候,都会同时复制一份到撤销段中。一来,可以方便对数据块修改的时候,其他用户访问该数据块;二来,如果需要回滚的时候,可以利用撤销段的这些数据来回滚。而且这些数据会保存在撤销段中一段时间,直到被重写。为此,可以通过这些undo数据来进行事务故障的恢复。
一、准备
1、undo
既然前面所说了,闪回技术除了闪回删除之外是利用撤销段的数据进行恢复的。为此,撤销段必须存在,并且应该具有足够的空间以满足闪回的需求。需要注意的是下面三个参数:
SQL> show parameter undo;
NAME TYPE VALUE
------------------------------------ ----------- ------
undo_management string AUTO ---撤销段的管理方式;
undo_retention integer 900 ---撤销段数据的保留时间,过了这个时间,就会过期;
undo_tablespace string UNDOTBS1---撤销段表空间;
2、启动
需要在加载的状态下,启动闪回和附加日志。并且需要让数据库处于归档模式。
alter database flashback on;---启动闪回;
alter database add supplemental log data;---添加附加日志;
alter database archivelog;---归档模式;
---可以通过下面的方式查看上面这些的状态;
SQL> select log_mode,flashback_on,supplemental_log_data_min,supplemental_log_data_pk,supplemental_log_data_ui from v$database;
LOG_MODE FLASHBACK_ON SUPPLEME SUP SUP
------------ ------------------ -------- --- ---
ARCHIVELOG YES YES NO NO
/*supplemental_log_data_min,supplemental_log_data_pk,supplemental_log_data_ui
*上面三个有一个为YES,表示附加日志已经启动;
*/
3、权限
Oracle Flashback Query and Oracle Flashback Version Query需要flashback any table权限;
Oracle Flashback Transaction Query需要select any transaction权限;
调用DBMS_FLASHBACK包,需要该包的execute权限;
闪回归档需要flashback archive administer权限;
grant flashback any table to sh;---授予flashback any table 权限;
grant select any transaction to sh;---授予select any transaction 权限;
grant execute on dbms_flashback to sh;---授予dbms_flashabck的execute权限;
grant flashback archive administer to sh;---授予flashback archive administer权限;
二、闪回查询
闪回查询的一个基本功能就是,确定什么时候进行了什么操作。可以通过下面四种方法来查询过去的信息
- select ..as of scn|timestamp....;
- select versions_startscn,versions_starttime,versions_endscn,versions_endtime,versions_xid,versions_operation....VERSIONS {BETWEEN {SCN | TIMESTAMP} start AND end };
- ORA_ROWSCN;
- flashback_transaction_query;
具体操作如下:
---准备数据
SQL>create table t(
2 id int,
3 num int);
SQL>begin
2 insert into t
3 select 1,100 from dual union all
4 select 2,200 from dual;
5 commit;
6 update t set num = 1111 where id =2;
7 commit;
8 update t set num = 2222 where id =2;
9 commit;
10 delete from t where id =2;
11 commit;
12 insert into t
13 select 2,3333 from dual;
14 commit;
15 end;
16 /
闪回查询:select ...as of scn|timestamp..
SQL> select * from t as of scn 2406855 ;
ID NUM
---------- ----------
1 100
2 3333
闪回版本查询:从下面的结果中可以看到,有两行的versions_starttime一样,但是versions_endtime一个为空,一个不为空,其实这表示这两行数据是同时插入的,也就是在插入完第二行数据的时候才commit。另外,对于同一行数据,在插入之后先后经过了两次的UPDATE,一次DELETE。DELETE的versions_endtime为空表示该行数据已经被删除,不在存在。
SQL> col versions_xid format a20;
SQL> col versions_starttime format a30;
SQL> col versions_endtime format a30;
SQL> set linesize 150 pagesize 100;
SQL> select versions_xid,versions_startscn,versions_starttime,versions_endscn,versions_endtime,versions_operation,id,num from t versions between scn 2
406798 and 2406855 order by versions_startscn;
VERSIONS_XID VERSIONS_STARTSCN VERSIONS_STARTTIME VERSIONS_ENDSCN VERSIONS_ENDTIME V ID NUM
-------------------- ----------------- ------------------------------ --------------- ------------------------------ - ---------- ----------
08000E00C5050000 2406800 05-8月 -13 10.40.58 下午 I 1 100
08000E00C5050000 2406800 05-8月 -13 10.40.58 下午 2406823 05-8月 -13 10.41.31 下午 I 2 200
03002100E6050000 2406823 05-8月 -13 10.41.31 下午 2406830 05-8月 -13 10.41.46 下午 U 2 1111
08001900C4050000 2406830 05-8月 -13 10.41.46 下午 2406846 05-8月 -13 10.42.04 下午 U 2 2222
05001200E1060000 2406846 05-8月 -13 10.42.04 下午 D 2 2222
08000500C6050000 2406855 05-8月 -13 10.42.28 下午 I 2 3333
通过flashback_transaction_query查询:可以利用该视图,查看到对应变化的事务ID,以及undo_sql,可以进行事务回滚。
SQL> col xid format A20;
SQL> col row_id format A20;
SQL> col undo_sql format A40;
SQL> set linesize 150 pagesize 100;
SQL> col table_name format A10;
SQL> col table_owner format A10;
SQL> col logon_user format a10;
SQL> col operation format A6;
SQL> select xid,start_scn,commit_scn,undo_change#,operation,row_id,undo_sql from flashback_transaction_query where table_name ='T' order by start_scn;
XID START_SCN COMMIT_SCN UNDO_CHANGE# OPERAT ROW_ID UNDO_SQL
-------------------- ---------- ---------- ------------ ------ -------------------- ----------------------------------------
08000E00C5050000 2406798 2406800 2 INSERT AAASX1AAEAAAAI8AAB delete from "SH"."T" where ROWID = 'AAAS
X1AAEAAAAI8AAB';
08000E00C5050000 2406798 2406800 1 INSERT AAASX1AAEAAAAI8AAA delete from "SH"."T" where ROWID = 'AAAS
X1AAEAAAAI8AAA';
03002100E6050000 2406821 2406823 1 UPDATE AAASX1AAEAAAAI8AAB update "SH"."T" set "NUM" = '200' where
ROWID = 'AAASX1AAEAAAAI8AAB';
08001900C4050000 2406828 2406830 1 UPDATE AAASX1AAEAAAAI8AAB update "SH"."T" set "NUM" = '1111' where
ROWID = 'AAASX1AAEAAAAI8AAB';
05001200E1060000 2406844 2406846 1 DELETE AAASX1AAEAAAAI8AAB insert into "SH"."T"("ID","NUM") values
('2','2222');
08000500C6050000 2406853 2406855 1 INSERT AAASX1AAEAAAAI8AAC delete from "SH"."T" where ROWID = 'AAAS
X1AAEAAAAI8AAC';
利用ora_rowscn查询:ora_rowscn表示的是对应行最近commit的时间。不过,需要注意的是,如果你想把数据恢复到ORA_ROWSCN指定的时间的话,有可能会不成功,因为考虑到并发性因素,可能在数据恢复的过程中,ORA_ROWSCN已经发生了变化,因为其他用户可能修改该行数据,并且提交了,改变了ORA_ROWSCN。
SQL> select ora_rowscn,id,num from t;
ORA_ROWSCN ID NUM
---------- ---------- ----------
2406855 1 100
2406855 2 3333