一、先建一个会话,以scott用户登录
connect scott/tiger
select * from emp;
update emp set sal=4000 where empno=7788;
先不提交这个事务,在另外窗口新开session,使用SYS用户查询相关信息,进行进一步的分析研究
XIDUSN XIDSLOT XIDSQN UBABLK UBAFIL UBAREC
---------- ---------- ---------- ---------- ---------- ----------
8 32 1895 4917 2 45
SQL> select usn,writes,rssize,xacts,hwmsize,shrinks,wraps from v$rollstat;
USN WRITES RSSIZE XACTS HWMSIZE SHRINKS WRAPS
---------- ---------- ---------- ---------- ---------- ---------- ----------
0 5160 385024 0 385024 0 0
1 156 1171456 0 1171456 0 0
2 296 1171456 0 1171456 0 0
3 478 1171456 0 1171456 0 0
4 472 1171456 0 1171456 0 0
5 264 1171456 0 1171456 0 0
6 1528 253952 0 253952 0 0
7 284 1171456 0 1171456 0 0
8 462 1171456 1 1171456 0 0
9 308 1171456 0 1171456 0 0
10 574 188416 0 188416 0 0
TRN TBL::,也就是这个回滚段中记录的事务列表
index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt
------------------------------------------------------------------------------------------------
0x00 9 0x00 0x0768 0xffff 0x0000.002030ff 0x00000000 0x0000.000.00000000 0x00000000 0x00000000 1390029178
0x20 10 0x80 0x0767 0x0002 0x0000.0020312a 0x00801335 0x0000.000.00000000 0x00000001 0x00000000 0
state状态9为非活动事务.state为10为活动事物
index字段就是事务表中的slot号,dba 包含这个活动事务的block地址
在这个例子中index为0x20,转换为10进制2*16=32,刚好与 XIDSLOT 相等
再来看dba,0x00801335 转换为二进制位d0000 0000 1000 0000 0001 0011 0011 0101,
DBA代表数据块的存储地址,由10位文件号+22位数据块(BLOCK)组成。这个是ORACLE内部决定的
前十位0000 0000 10转10进制为2,后面20位转十进制为4917 ,刚好与v$transaction中的结果匹配。
二、scoott不提交update的动作,继续执行下面的命令
SQL> update emp set sal=4000 where empno=7900;
SQL> update emp set sal=4000 where empno=7902;
SQL> select xidusn,xidslot,xidsqn,ubablk,ubafil,ubarec FROM v$transaction;
XIDUSN XIDSLOT XIDSQN UBABLK UBAFIL UBAREC
---------- ---------- ---------- ---------- ---------- ----------
8 32 1895 4917 2 47
可以发现XID与一中XID相同,说明他们在同一个事物中。
UBA------该事务的最后一个UNDO RECORD的地址(一个事务的UNDO,由多个UNDO RECORD组成, 一个UNDO BLOCK里面包含多个UNDO RECORD)
SQL> alter system dump undo header '_SYSSMU8$';
System altered.
SQL> alter system dump datafile 2 block 4917;
在trc文件中找到
UNDO BLK:
xid: 0x0008.020.00000767 seq: 0x16d cnt: 0x2f irb: 0x2f icl: 0x0 flg: 0x0000
其中的xid = Undo segment no.Slotno.sequence no
Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset
0x01 0x1f8c 0x02 0x1ee8 0x03 0x1e8c 0x04 0x1de8 0x05 0x1d8c
0x06 0x1ce8 0x07 0x1c8c 0x08 0x1be8 0x09 0x1b8c 0x0a 0x1ae8
0x0b 0x1a8c 0x0c 0x19e8 0x0d 0x198c 0x0e 0x18e8 0x0f 0x188c
0x10 0x17e8 0x11 0x178c 0x12 0x16e8 0x13 0x168c 0x14 0x15e8
0x15 0x158c 0x16 0x14e8 0x17 0x148c 0x18 0x13e8 0x19 0x138c
0x1a 0x12e8 0x1b 0x128c 0x1c 0x11e8 0x1d 0x118c 0x1e 0x10e8
0x1f 0x108c 0x20 0x0fe8 0x21 0x0f8c 0x22 0x0ee8 0x23 0x0e8c
0x24 0x0de8 0x25 0x0d8c 0x26 0x0ce8 0x27 0x0c8c 0x28 0x0be8
0x29 0x0b8c 0x2a 0x0ae8 0x2b 0x0a8c 0x2c 0x09ac 0x2d 0x0910
0x2e 0x08a4 0x2f 0x084c
irb: 0x2f 指的是回滚段中记录的最近未提交变更开始之处,如果开始回滚,这是起始的搜索点
* Rec #0x2f slt: 0x20 objn: 51148(0x0000c7cc) objd: 51148 tblspc: 4(0x00000004)
* Layer: 11 (Row) opc: 1 rci 0x2e --------偏移量
Undo type: Regular undo Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo
op: 0x02 ver: 0x01
op: C uba: 0x00801335.016d.2e
KDO Op code: URP row dependencies Disabled
xtype: XAxtype KDO_KDOM2 flags: 0x00000080 bdba: 0x01000020 hdba: 0x0100001b
itli: 1 ispac: 0 maxfr: 4858
tabn: 0 slot: 12(0xc) flag: 0x2c lock: 0 ckix: 191
ncol: 8 nnew: 1 size: 0
vector content: -----------前镜像的值
col 5: [ 2] c2 1f
因为update的是数值的,所以可以用下面的过程计算出该值
SQL> set serveroutput on ; -- -----使用set serveroutput on 命令设置环境变量serveroutput为打开状态,从而使得pl/sql程序能够在SQL*plus中输出结果 ,使用函数 dbms_output.put_line()可以输出参数的值。SQL> declare n number;
2 begin
3 dbms_stats.convert_raw_value('c21f',n);
4 dbms_output.put_line(n);
5 end;
6 /
3000
上面这个过程能把dump出来的东西还原回去
同时我们也可以认证:
SQL> select dump(3000,16) from dual; 16表示16进制
DUMP(3000,16)
------------------
Typ=2 Len=2: c2,1f 结果与上面是一致的