修改的数据没有提交之前,其他会话是看不到被修改的数据,被修改之前的数据会存放在UNDO里面,那么ORACLE是通过什么的方式找到存放在UNDO里面的数据呢?下面通过具体例子来说明
首先开启两个会话,其中第一个会话只更新数据(分两种情况,一、只更新一次, 二、连续更新多次)。第二个会话查询会话一更新的数据,查看是否能查到。
1、----创建测试表并插入数据-----
SQL> create table my_test(id int, name varchar2(20));
Table created.
SQL> insert into my_test values (1,'a');
1 row created.
SQL> commit;
Commit complete.
SQL>
会话1更新数据不提交
SQL>
SQL> update my_test set id = 2 ;
1 row updated.
SQL> @pid
SID SERIAL# PID SPID
---------- ---------- ---------- ------------------------
125 5 19 26271
SQL> select * from my_test;
ID NAME
---------- --------------------
2 a
SQL>
2、会话2查询my_test表的数据
SQL> @pid
SID SERIAL# PID SPID
---------- ---------- ---------- ------------------------
150 15 31 26455
SQL> select * from my_test;
ID NAME
---------- --------------------
1 a
SQL>
可以看到会话2(sid = 150)查看到的ID=1, 会话1(sid = 125)已经把ID更新为2,但是并没有提交。所以会话2看到ID还是更新之前的数据。ORACLE是通过UNDO的机制,把更新之后的数据写入UNDO。那么会话2是怎么通过UNDO找到会话1更新之前的数据呢?
3、查找会话1产生的UNDO数据有两种方式,由于我这是测试库,库中只有会话1更新了my_test表没有提交,不存在其他未提交事务。
3.1、直接通过UNDO的相关视图查找会话1的产生的UNDO数据。
SQL> select addr, XIDUSN,XIDSLOT,XIDSQN,UBAFIL,UBABLK,UBASQN,UBAREC from v$transaction;
ADDR XIDUSN XIDSLOT XIDSQN UBAFIL UBABLK UBASQN UBAREC
---------------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
000000007CB381A8 26 30 12516 19 134 1661 6
SQL>
其中
XIDUSN 回滚段号
XIDSLOT 槽号
XIDSQN 覆盖次数
UBAFIL 回滚文件号
UBABLK 回滚块号
UBAREC 代表REC记录号
首先通过UNDO的文件号和块号查看UNDO的数据
SQL> alter system dump datafile 19 block 134;
System altered.
SQL> col VALUE for a60
SQL> select value from v$diag_info where name = 'Default Trace File';
VALUE
------------------------------------------------------------
/u01/app/diag/rdbms/qxy/QXY/trace/QXY_ora_26545.trc
SQL>
Block dump from disk:
buffer tsn: 11 rdba: 0x04c00086 (19/134) <====19号文件134块
scn: 0x0000.027f8d4f seq: 0x01 flg: 0x04 tail: 0x8d4f0201
frmt: 0x02 chkval: 0x7538 type: 0x02=KTU UNDO BLOCK <=====块类型是UNDO
Hex dump of block: st=0, typ_found=1
********************************************************************************
UNDO BLK:
xid: 0x001a.01e.000030e4 seq: 0x67d cnt: 0x6 irb: 0x6 icl: 0x0 flg: 0x0000
Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset
---------------------------------------------------------------------------
0x01 0x1f40 0x02 0x1e98 0x03 0x1de0 0x04 0x1d38 0x05 0x1c90
0x06 0x1bf0
其中
xid 0x001a.01e.000030e4分为三个部分,第一部分代表XIDUSN=0x001a转换成10进制为26。
第二部分代表XIDSLOT=01e转换成10进制为30, 第三部分为XIDSQN=30e4转换成10进制为12516
可以看到这三个部分和v$transaction查看到的回滚段信息是一致的。
seq 对应v$transaction里面的UBASQN,0x67d转换成10进制为1661
irb代表该undo块上面最新的事务记录号0x6和v$transaction里面的UBAREC=6对应。
查看rec# = 0x6的undo数据
*-----------------------------
* Rec #0x6 slt: 0x1e objn: 136312(0x00021478) objd: 136312 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x00 <======rci=0x00代表上面没有更新的回滚数据
Undo type: Regular undo Begin trans Last buffer split: No (因为会话1只更新了一次)
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000Ext idx: 0
flg2: 0
*-----------------------------
uba: 0x04c00085.067d.30 ctl max scn: 0x0000.027f8ac6 prv tx scn: 0x0000.027f8acf
txn start scn: scn: 0x0000.027f8d4f logon user: 0
prev brb: 79691908 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x03 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: Z
KDO Op code: URP row dependencies Disabled <======URP 代表更新数据
xtype: XA flags: 0x00000000 bdba: 0x00420bb9 hdba: 0x00420bb8
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 0
ncol: 2 nnew: 1 size: 0
col 0: [ 2] c1 02 <======更新之前的数据为 c102
End dump data blocks tsn: 11 file#: 19 minblk 134 maxblk 134
通过Rec #0x6上面的数据可以看到该UNDO块上面的保存的数据为c102,把c102转换成10进制如下
SQL> select utl_raw.cast_to_number('c102') from dual;
UTL_RAW.CAST_TO_NUMBER('C102')
------------------------------
1
SQL>
可以看到undo块上面保存的是会话1更新之前的数据。上面是通过v$transaction视图中的UBAFIL、UBABLK确定的文件号和块号,然后再通过dump该文件号和块号得到了会话1更新之前的数据。同样也可以通过v$transaction中的XIDUSN、XIDSLOT、XIDSQN确定回滚块的信息
通过v$transaction视图查看到XIDUSN=26,代表着回滚段为26号,把XIDUSN=26的回滚段dump出来
SQL> select usn,name from v$rollname where usn = 26;
USN NAME
---------- ------------------------------
26 _SYSSMU26_2510430623$
SQL>
SQL> alter system dump undo header "_SYSSMU26_2510430623$";
System altered.
SQL>
SQL> col VALUE for a60
SQL> select value from v$diag_info where name = 'Default Trace File';
VALUE
------------------------------------------------------------
/u01/app/diag/rdbms/qxy/QXY/trace/QXY_ora_26698.trc
SQL>
查看/u01/app/diag/rdbms/qxy/QXY/trace/QXY_ora_26698.trc内容
********************************************************************************
Undo Segment: _SYSSMU26_2510430623$ (26)
********************************************************************************
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 3 #blocks: 143
last map 0x00000000 #maps: 0 offset: 4080
Highwater:: 0x04c00086 ext#: 2 blk#: 6 ext size: 128
#blocks in seg. hdr's freelists: 0
#blocks below: 0
mapblk 0x00000000 offset: 2
Unlocked
Map Header:: next 0x00000000 #extents: 3 obj#: 0 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x028000f1 length: 7
0x028000f8 length: 8
0x04c00080 length: 128
TRN TBL::
index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt
------------------------------------------------------------------------------------------------
0x00 9 0x00 0x30e0 0x0006 0x0000.027f8c6c 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x01 9 0x00 0x30e6 0x001d 0x0000.027f8cf0 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x02 9 0x00 0x30df 0x001a 0x0000.027f8c06 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x03 9 0x00 0x30eb 0x001b 0x0000.027f8c1c 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x04 9 0x00 0x30e3 0xffff 0x0000.027f8d3b 0x04c00086 0x0000.000.00000000 0x00000002 0x00000000 1582741174
0x05 9 0x00 0x30e5 0x0021 0x0000.027f8b5d 0x04c00081 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x06 9 0x00 0x30e5 0x0017 0x0000.027f8c7b 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x07 9 0x00 0x30e5 0x0005 0x0000.027f8b4c 0x04c00081 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x08 9 0x00 0x30e7 0x0011 0x0000.027f8c9c 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x09 9 0x00 0x30e1 0x0001 0x0000.027f8ccf 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x0a 9 0x00 0x30e7 0x0016 0x0000.027f8b1b 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x0b 9 0x00 0x30ea 0x000a 0x0000.027f8b05 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x0c 9 0x00 0x30e5 0x000d 0x0000.027f8be4 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x0d 9 0x00 0x30ed 0x000e 0x0000.027f8bf2 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x0e 9 0x00 0x30df 0x0002 0x0000.027f8bfa 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x0f 9 0x00 0x30e7 0x0012 0x0000.027f8b86 0x04c00081 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x10 9 0x00 0x30e4 0x001f 0x0000.027f8af0 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x11 9 0x00 0x30e6 0x0009 0x0000.027f8ca4 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x12 9 0x00 0x30e3 0x0014 0x0000.027f8b93 0x04c00085 0x0000.000.00000000 0x00000002 0x00000000 1582741174
0x13 9 0x00 0x30e7 0x001c 0x0000.027f8c47 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x14 9 0x00 0x30e4 0x0018 0x0000.027f8ba4 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x15 9 0x00 0x30e2 0x0010 0x0000.027f8ae4 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x16 9 0x00 0x30e7 0x0019 0x0000.027f8b33 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x17 9 0x00 0x30e3 0x0008 0x0000.027f8c8c 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x18 9 0x00 0x30e7 0x000c 0x0000.027f8bbf 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x19 9 0x00 0x30eb 0x0007 0x0000.027f8b46 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x1a 9 0x00 0x30ea 0x0003 0x0000.027f8c0f 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x1b 9 0x00 0x30dc 0x0020 0x0000.027f8c2e 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x1c 9 0x00 0x30e7 0x0000 0x0000.027f8c5a 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x1d 9 0x00 0x30e2 0x0004 0x0000.027f8d16 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
==>0x1e 10 0x80 0x30e4 0x0002 0x0000.027f8d4f 0x04c00086 0x0000.000.00000000 0x00000001 0x00000000 0
0x1f 9 0x00 0x30e7 0x000b 0x0000.027f8af8 0x04c00084 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x20 9 0x00 0x30e3 0x0013 0x0000.027f8c40 0x04c00085 0x0000.000.00000000 0x00000001 0x00000000 1582741174
0x21 9 0x00 0x30de 0x000f 0x0000.027f8b65 0x04c00081 0x0000.000.00000000 0x00000001 0x00000000 1582741174
查看回滚段的RN TBL::信息,发现index=0x1e这行的state=10,10代表是活动事物。dba(data block address)为0x04c00086,意思就是该事物对应的undo数据在0x4c00086上面。把0x4c00086转换成文件号和块号,如下:
SQL> select to_number('4c00086','xxxxxxxx') from dual;
TO_NUMBER('4C00086','XXXXXXXX')
-------------------------------
79691910
SQL> select dbms_utility.data_block_address_file(79691910) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(79691910)
----------------------------------------------
19
SQL> select dbms_utility.data_block_address_block(79691910) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(79691910)
-----------------------------------------------
134
SQL>
可以看到dba转换成10文件号和块号之后正是v$transaction中的DBAFIL、DBABLK。找到undo的文件号和块号之后就可以
按照上面的方法找到undo块上面对应的会话1更新前的数据
wrap#=0x30e3代表v$transaction里面的XIDSQN,转换成10进制为12515。
3.2 方法一是直接通过v$transaction视图里面的数据来查找会话1更新之前的undo数据。但是会话2查询my_test数据时不会通过 v$transaction里面去查找undo数据。会话2也不会知道v$transaction里面哪行数据对应my_test表的前镜像。
会话2查询数据的过程如下:
查询my_test表时,首先找到my_test表对应的数据块
SQL> select dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) from my_test;
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ ------------------------------------
1 134073
SQL>
因为会话1更新了1号文件134073的块,所以块上面会有事物信息,查看上面事物信息
SQL>
SQL> alter system dump datafile 1 block 134073;
System altered.
SQL> select value from v$diag_info where name = 'Default Trace File';
VALUE
--------------------------------------------------------------------------------
/u01/app/diag/rdbms/qxy/QXY/trace/QXY_ora_26859.trc
SQL>
查看/u01/app/diag/rdbms/qxy/QXY/trace/QXY_ora_26859.trc内容
Block dump from disk:
buffer tsn: 0 rdba: 0x00420bb9 (1/134073)
scn: 0x0000.027f8d66 seq: 0x01 flg: 0x04 tail: 0x8d660601
frmt: 0x02 chkval: 0xa68e type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x00007FA900615A00 to 0x00007FA900617A00
7FA9006179F0 00000000 0202022C 610103C1 8D660601 [....,......a..f.]
Block header dump: 0x00420bb9
Object id on Block? Y
seg/obj: 0x21478 csc: 0x00.27f8d66 itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x001a.000.000030df 0x04c00084.067d.03 C--- 0 scn 0x0000.027f8a36
0x02 0x001a.01e.000030e4 0x04c00086.067d.06 ---- 1 fsc 0x0000.00000000
可以看到Itl =0x02上面的Lck=1。说明该块上面有其他会话修改,并且没有提交。会话2访问该块的时候只能通过UBA(undo block address)的UNDO数据找到旧镜像。其中Xid =0x001a.01e.000030e4就是对应v$transaction的XIDUSN、XIDSLOT、XIDSQN。转换成10进制分别为第一部分代表XIDUSN=0x001a转换成10进制为26。第二部分代表XIDSLOT=01e转换成10进制为30, 第三部分为XIDSQN=30e4转换成10进制为12516。和v$transaction里面看到的一样UBA的数据为0x04c00086.067d.06其中第一部分为undo块的地址,转为文件号和块号如下:
SQL> select to_number('4c00086','xxxxxxxx') from dual;
TO_NUMBER('4C00086','XXXXXXXX')
-------------------------------
79691910
SQL> select dbms_utility.data_block_address_file(79691910) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(79691910)
----------------------------------------------
19
SQL> select dbms_utility.data_block_address_block(79691910) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(79691910)
-----------------------------------------------
134
SQL>
第二部分为UBASQN=067d转换成10进制为 1661。
第三部分为UBAREC=6进制也为6。
可以看到数据块上面对应的事务信息和v$transaction里面查到的数据完全一致,然后再按照方法一的方式找到UNDO上面的数据。
所以会话2查看my_test表内容时发现数据块上面存在事物信息, 然后根据事物的xid以及uba信息找到保存着undo块上面的数据,然后再和没有修改的列组成查询返回的数据。就得到的如下数据
SQL> select * from my_test;
ID NAME
---------- --------------------
1 a
SQL>
4、还有文章开头提到的如果会话1连续更新多次,UNDO上面的数据是怎么保存的呢?
SQL> update my_test set id = 3;
1 row updated.
SQL> update my_test set id = 4;
1 row updated.
SQL> update my_test set id = 5;
1 row updated.
SQL> @pid
SID SERIAL# PID SPID
---------- ---------- ---------- ------------------------
125 5 19 26271
SQL>
会话1又更新了3次没有提交。然后再次dump数据块
SQL> alter system dump datafile 1 block 134073;
System altered.
SQL>
查看dump文件的事务信息如下:
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x001a.000.000030df 0x04c00084.067d.03 C--- 0 scn 0x0000.027f8a36
0x02 0x001a.01e.000030e4 0x04c00086.067d.09 ---- 1 fsc 0x0000.00000000
bdba: 0x00420bb9
data_block_dump,data header at 0x7fa900615a5c
===============
tsiz: 0x1fa0
hsiz: 0x14
pbl: 0x7fa900615a5c
76543210
和第一次dump的对比
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x001a.000.000030df 0x04c00084.067d.03 C--- 0 scn 0x0000.027f8a36
0x02 0x001a.01e.000030e4 0x04c00086.067d.06 ---- 1 fsc 0x0000.00000000
可以看到xid的数据是一致的,uba中的前两个部分也是一致的,只有第三个部分UBASQN发生了变化,由原来的6变成了9。
Uba的第一部分并没有发生变化,所有UNDO对应的文件号和块号是没有发生变化的。再次dump undo块查看内容
SQL> alter system dump datafile 19 block 134;
System altered.
SQL> select value from v$diag_info where name = 'Default Trace File';
VALUE
--------------------------------------------------------------------------------
/u01/app/diag/rdbms/qxy/QXY/trace/QXY_ora_29036.trc
SQL>
查看UNDO BLK信息
UNDO BLK:
xid: 0x001a.01e.000030e4 seq: 0x67d cnt: 0x9 irb: 0x9 icl: 0x0 flg: 0x0000
Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset
---------------------------------------------------------------------------
0x01 0x1f40 0x02 0x1e98 0x03 0x1de0 0x04 0x1d38 0x05 0x1c90
0x06 0x1bf0 0x07 0x1b7c 0x08 0x1b08 0x09 0x1a94
*-----------------------------
和第一次dump的对比
UNDO BLK:
xid: 0x001a.01e.000030e4 seq: 0x67d cnt: 0x6 irb: 0x6 icl: 0x0 flg: 0x0000
Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset
---------------------------------------------------------------------------
0x01 0x1f40 0x02 0x1e98 0x03 0x1de0 0x04 0x1d38 0x05 0x1c90
0x06 0x1bf0
可以发现变为的为Rec有原来的最大0x06变成了现在的0x09,和Uba的变化正好相对应。
查看Rec=9的UNDO内容
*-----------------------------
* Rec #0x9 slt: 0x1e objn: 136312(0x00021478) objd: 136312 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x08 <=====指向上一个指针
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
compat bit: 4 (post-11) padding: 1
op: C uba: 0x04c00086.067d.08
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00420bb9 hdba: 0x00420bb8
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 2 ckix: 0
ncol: 2 nnew: 1 size: 0
col 0: [ 2] c1 05 <====转换成10进制为4
SQL> select utl_raw.cast_to_number('c105') from dual;
UTL_RAW.CAST_TO_NUMBER('C105')
------------------------------
4
SQL>
rci=0x08 代表指向上一个指针。查看Rec=8 的内容
* Rec #0x8 slt: 0x1e objn: 136312(0x00021478) objd: 136312 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x07 <=====指向上一个指针
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
compat bit: 4 (post-11) padding: 1
op: C uba: 0x04c00086.067d.07
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00420bb9 hdba: 0x00420bb8
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 2 ckix: 0
ncol: 2 nnew: 1 size: 0
col 0: [ 2] c1 04 <====转换成10进制为3
rci=0x07 代表指向上一个指针。查看Rec=7 的内容
*-----------------------------
* Rec #0x7 slt: 0x1e objn: 136312(0x00021478) objd: 136312 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x06 <=====指向上一个指针
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
compat bit: 4 (post-11) padding: 1
op: C uba: 0x04c00086.067d.06
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00420bb9 hdba: 0x00420bb8
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 2 ckix: 0
ncol: 2 nnew: 1 size: 0
col 0: [ 2] c1 03 <====转换成10进制为2
rci=0x06 代表指向上一个指针。查看Rec=6 的内容
*-----------------------------
* Rec #0x6 slt: 0x1e objn: 136312(0x00021478) objd: 136312 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x00 <=====上一个指针为NULL
Undo type: Regular undo Begin trans Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000Ext idx: 0
flg2: 0
*-----------------------------
uba: 0x04c00085.067d.30 ctl max scn: 0x0000.027f8ac6 prv tx scn: 0x0000.027f8acf
txn start scn: scn: 0x0000.027f8d4f logon user: 0
prev brb: 79691908 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x03 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: Z
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00420bb9 hdba: 0x00420bb8
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 0
ncol: 2 nnew: 1 size: 0
col 0: [ 2] c1 02 <====转换成10进制为1
rci=0x00 意味着Rec=6就是UNDO上面最原始的数据了,该数据内容为c102转换成10进制为1,这个1也正是会话1第一次更新的数据。
所以,一个会话如果有多次更新没有提交,那么它会在undo里面存在多份更新之后的数据,这些数据通过指针的方式串联起来,如果其他会话需要使用undo数据的时候就要根据指针找到链表头即为需要的UNDO数据。