oracle设置为脏读,Oracle数据库通过undo保证一致性读和不发生脏读-Oracle

Oracle数据库通过undo保证一致性读和不发生脏读

不发生脏读,用户A对表更新了,没有提交,用户B对进行查询,没有提交的更新不能出现在用户的查询结果中。

实例模拟:表test中的数据如下

1,用户A查询:SQL> select * from test;

ID NAME

———- ———-

1 A

2 B

2,用户B:update test set name=’C’ where id=1;没有提交

www.2cto.com

3,用户A再次查询:SQL> select * from test;

ID NAME

———- ———-

1 A

2 B

查询到数据块的信息

select id, rowid, dbms_rowid.rowid_relative_fno(rowid) fn,dbms_rowid.rowid_block_number(rowid) bk from test order by id

这时候dump 数据块(内存中的数据块) alter system dump datafile 4 block 6717,

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0x0003.02d.00000323  0x008001c5.0297.0d  C—    0  scn 0x0000.0022cf82

0x02   0x0006.020.00000320  0x0080048c.017d.03  —-    1  fsc 0x0000.00000000

。。。。

block_row_dump:

tab 0, row 0, @0x1f90

tl: 8 fb: –H-FL– lb: 0x2  cc: 2

col  0: [ 2]  c1 02

col  1: [ 1]  43

tab 0, row 1, @0x1f88

tl: 8 fb: –H-FL– lb: 0x0  cc: 2

col  0: [ 2]  c1 03

col  1: [ 1]  42

end_of_block_dump

发现id=1的值已经更改了,43(16进制对应的是C),那么A用户得到值为什么还是A呢

这是因为Oracle发现这条数据有lb: 0x2 对应的是ITL,从ltl为0x02的记录看到flag为—-,表示有事务标记,数据被加锁,需要从undo段的uba(undo block address)中读取。

在undo段中对应的块信息是0x0080048c,这里的数字是16进制的,先将其转为10进制:

www.2cto.com

select to_number(‘0080048c’,’XXXXXXXXXXXXXXX’) from dual 得到值8389772

在通过下面的语句得到数据块信息:select dbms_utility.data_block_address_file(8389772), dbms_utility.data_block_address_block(8389772) from dual;

将其内容dump出来

。。。。

KDO Op code:  21 row dependencies Disabled

xtype: XAxtype KDO_KDOM2 flags: 0x00000080  bdba: 0x01001a3d  hdba: 0x01001a3b

itli: 2  ispac: 0  maxfr: 4858

vect = 3

col  1: [ 1]  41

End dump data blocks tsn: 1 file#: 2 minblk 1164 maxblk 1164

发现其值为41(16进制对应的是A),所以用户A看的值为A。

假设某一个用户A在6点对某一个表发出了一个查询数据量很大的数据,需要15分钟才能把结果完全查询出来,在这期间,6点10分用户B对数据进行了更新并提交了,用户A查询的结果仍然是6点时候的表的数据,用户B更新的数据不出现在用户A的查询结果中,这就是一致性读。

实例模拟:  www.2cto.com

1,用户查询一个需要长时间运行的报表:

SQL> variable c refcursor;

SQL> exec open :c for select * from test;

PL/SQL procedure successfully completed.

【这里打开cursor但是不取数据,暂停,然后让用户B更新数据】

2,用户B :update test set name=’C’ where id=1;并且提交。

3,SQL> print :c;

ID NAME

———- ———-

1 A

2 B

用户B更新数据而且提交了,但是发现用户A得到的结果集仍然是刚开始执行是表中的数据结果。

www.2cto.com

其原理是用户A在执行开始的时候会保存当时的SCN,在每次从数据块读的时候,会比较保存的SCN和数据块的SCN,如果发现数据块的SCN比保存的SCN小,则数据没有变化,直接从数据块读,如果数据块的大,则需要从undo段中读取。select dbms_flashback.get_system_change_number from dual;可以看到当前的SCN.

一个查询如果耗费很长时间,而查询的结果在查询的阶段被更改了,而且对应着undo段的数据已经被清理了,就会发生Oracle中著名的ORA-013555: snapshot too old(快照太久)错误。

如果一条数据在一个时间段被更新多次并提交了,后放入undo段的块会记录相对以的块上次放在undo段中的块地址,从而可以一直寻找到比开始查询时候记录的SCN小的那个undo段中的数据块。

作者 kkdelta

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值