oracle通过undo保证一致性读和不发生脏读

1.不发生脏读

例如:用户A对表更新了,没有提交,用户B对进行查询,没有提交的更新不能出现在用户的查询结果中

举例并通个dump数据块说明避免脏读的原理

创建测试表,并插入两条记录,会话A执行更新但不提交

  1. SQL>select*from test;
  2. ID NAME
  3. --------------------
  4. 1 A
  5. 2 B
  6. SQL> update test set name='C'where id=2;
  7. 1 row updated.

会话B查询,数据没变

  1. SQL>select*from test;
  2. ID NAME
  3. --------------------
  4. 1 A
  5. 2 B

通过下面sql语句查询数据所在的数据文件和块号,并进行dump

  1. SQL>select id, rowid, dbms_rowid.rowid_relative_fno(rowid) fn,dbms_rowid.rowid_block_number(rowid) bk from test order by id;
  2. ID ROWID FN BK
  3. ------------------------------------------------
  4. 1AAAzkeAAIAAAACDAAA8131
  5. 2AAAzkeAAIAAAACDAAB8131
  6. SQL> alter system dump datafile 8 block 139;
  7. System altered.

未提交的数据块dump结果

  1. ItlXidUbaFlagLckScn/Fsc
  2. 0x010x0002.001.000a90a20x00c00093.9f1d.16 C---0 scn 0x0000.395178de
  3. 0x020x0007.010.000a93c50x00c00f4b.9f5d.34----1 fsc 0x0000.00000000
  4. ---上面事务槽中Flag为----从0x00c00f4b undo地址中读取
  5. bdba:0x0200008b
  6. data_block_dump,data header at 0x7fb742fc8a64
  7. ===============
  8. tsiz:0x1f98
  9. hsiz:0x16
  10. pbl:0x7fb742fc8a64
  11. 76543210
  12. flag=--------
  13. ntab=1
  14. nrow=2
  15. frre=-1
  16. fsbo=0x16
  17. fseo=0x1f88
  18. avsp=0x1f70
  19. tosp=0x1f70
  20. 0xe:pti[0] nrow=2 offs=0
  21. 0x12:pri[0] offs=0x1f90
  22. 0x14:pri[1] offs=0x1f88
  23. block_row_dump:---下面是表中数据行的dump
  24. tab 0, row 0,@0x1f90
  25. tl:8 fb:--H-FL-- lb:0x0 cc:2
  26. col 0:[2] c1 02
  27. col 1:[1]41--第一行 A
  28. tab 0, row 1,@0x1f88
  29. tl:8 fb:--H-FL-- lb:0x2 cc:2---lb为0x2说明未提交
  30. col 0:[2] c1 03
  31. col 1:[1]43---第二行 C
  32. end_of_block_dump

说明:通过上面的dump文件发现,数据已经被修改成C(43),但是Oracle发现这条数据有lb: 0x2 对应的是ITL,从ltl为0x02的记录看到flag为—-,表示有事务标记,数据被加锁,需要从undo段的uba(undo block address)中读取

undo段中对应的块信息为:0x00c00f4b,这里是十六进制,下面先转换成10进制

  1. SQL>select to_number('00c00f4b','XXXXXXXXXXXXXXX')from dual;
  2. TO_NUMBER('00C00F4B','XXXXXXXXXXXXXXX')
  3. ---------------------------------------
  4. 12586827
  5. 得到值为12586827

对undo块进行dump

  1. 在通过下面的语句得到数据块信息:
  2. SQL>select dbms_utility.data_block_address_file(12586827), dbms_utility.data_block_address_block(12586827)from dual;
  3. DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(12586827) DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(12586827)
  4. ---------------------------------------------------------------------------------------------
  5. 33915
  6. SQL>select file#,name from v$datafile where file#=3;
  7. FILE# NAME
  8. ------------------------------------------------------------
  9. 3/u01/app/oracle/oradata/FGLDB/undotbs01.dbf
  10. SQL> alter system dump datafile 3 block 3915;
  11. System altered.

dump内容如下:

  1. *-----------------------------
  2. *Rec#0x34 slt: 0x10 objn: 211231(0x0003391f) objd: 211231 tblspc: 4(0x00000004) --objd 为object id
  3. *Layer:11(Row) opc:1 rci 0x00
  4. Undo type:Regular undo Begin trans Last buffer split:No
  5. TempObject:No
  6. TablespaceUndo:No
  7. rdba:0x00000000Ext idx:0
  8. flg2:0
  9. *-----------------------------
  10. uba:0x00c00f4b.9f5d.25 ctl max scn:0x0000.39516d48 prv tx scn:0x0000.39516db3
  11. txn start scn: scn:0x0000.395178de logon user:83
  12. prev brb:12586818 prev bcl:0
  13. KDO undo record:
  14. KTB Redo
  15. op:0x03 ver:0x01
  16. compat bit:4(post-11) padding:1
  17. op: Z
  18. ArrayUpdate of 1 rows:
  19. tabn:0 slot:1(0x1) flag:0x2clock:0 ckix:12
  20. ncol:2 nnew:1 size:0
  21. KDO Op code:21 row dependencies Disabled
  22. xtype:XAxtype KDO_KDOM2 flags:0x00000080 bdba:0x0200008b hdba:0x0200008a
  23. itli:2 ispac:0 maxfr:4858
  24. vect =3
  25. col 1:[1]42--- undo中数据为B

从undo块中发现值为B(42),故其他用户看到的是B,看不到C,避免了脏读

附:提交后的数据块dump结果

  1. ItlXidUbaFlagLckScn/Fsc
  2. 0x010x0002.001.000a90a20x00c00093.9f1d.16 C---0 scn 0x0000.395178de
  3. 0x020x0007.010.000a93c50x00c00f4b.9f5d.34 C---0 scn 0x0000.39517d7a
  4. ---Flag为C---
  5. bdba:0x0200008b
  6. data_block_dump,data header at 0x7fa3c77efa64
  7. ===============
  8. tsiz:0x1f98
  9. hsiz:0x16
  10. pbl:0x7fa3c77efa64
  11. 76543210
  12. flag=--------
  13. ntab=1
  14. nrow=2
  15. frre=-1
  16. fsbo=0x16
  17. fseo=0x1f88
  18. avsp=0x1f70
  19. tosp=0x1f70
  20. 0xe:pti[0] nrow=2 offs=0
  21. 0x12:pri[0] offs=0x1f90
  22. 0x14:pri[1] offs=0x1f88
  23. block_row_dump:
  24. tab 0, row 0,@0x1f90
  25. tl:8 fb:--H-FL-- lb:0x0 cc:2
  26. col 0:[2] c1 02
  27. col 1:[1]41
  28. tab 0, row 1,@0x1f88
  29. tl:8 fb:--H-FL-- lb:0x0 cc:2--- lb为0x0
  30. col 0:[2] c1 03
  31. col 1:[1]43
  32. end_of_block_dump

总结:数据库通过判断数据块头部的ITL槽的信息来确定是否有未提交的事务,如果事务槽Flag为—-,则通过事务槽中的undo块地址查询到原来的数据,进而达到数据隔离的效果,避免脏读。

2.一致性读

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

  1. 用户A在执行开始的时候会记录当时的SCN号,如图中10021
  2. 在每次从数据块中读数据的时候会比较记录的SCN号和数据块事务槽中的SCN号(下一个事务的SCN号一定比当前的大)
    a.如果数据块中的SCN比当前分配的SCN号小,则认为该数据没有被修改,直接读取;
    b.如果数据块中的SCN号比当前分配的SCN大,则根据块中保存的地址去undo中读取当时分配SCN时间点的数据(根据undo数据块在内存中重新构造出该数据块,称为consistent read (CR)块)

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

    如果一条数据在查询期间被更新过多次并且提交,后放入undo段的块会记录相对的块上次放在undo段中的块地址,从而一路寻找到查询开始时间点在undo段中的数据块。

3. 事务槽(ITL)小解

ITL(Interested Transaction List)是Oracle数据块内部的一个组成部分,位于数据块头(block header),itl由xid,uba,flag,lck和scn/fsc组成,用来记录该块所有发生的事务,一个itl可以看作是一条事务记录。当然,如果这个事务已经提交,那么这个itl的位置就可以被反复使用了,因为itl类似记录,所以,有的时候也叫itl槽位。如果一个事务一直没有提交,那么,这个事务将一直占用一个itl槽位,itl里面记录了事务信息,回滚段的入口,事务类型等等。如果这个事务已经提交,那么,itl槽位中还保存的有这个事务提交时候的SCN号。

Xid:事务id,在回滚段事务表中有一条记录和这个事务对应
Uba:回滚段地址,该事务对应的回滚段地址

  • 第一段地址:回滚数据块的地址,包括回滚段文件号和数据块号
  • 第二段地址:回滚序列号
  • 第三段地址:回滚记录号
    –查看UBA
    SELECT UBAFIL undo_file_id,UBABLK undo_blk_num,UBASQN undo_segment_num,UBAREC undo_recode_num FROM v$transaction;

Flag:事务标志位。这个标志位就记录了这个事务的操作,各个标志的含义分别是:

  • —– = 事务是活动的,或者在块清除前提交事务
  • C— = 事务已经提交并且清除了行锁定。
  • -B– = this undo record contains the undo for this ITL entry
  • –U- = 事务已经提交(SCN已经是最大值),但是锁定还没有清除(快速清除)。
  • —T = 当块清除的SCN被记录时,该事务仍然是活动的,块上如果有已经提交的事务,

那么在clean ount的时候,块会被进行清除,但是这个块里面的事务不会被清除。

Lck:影响的记录数

Scn/Fsc:快速提交(Fast Commit Fsc)的SCN或者Commit SCN。

每条记录中的行级锁对应于Itl列表中的序号,即哪个事务在该记录上产生的锁。

关注公众号:数据库技术分享,不定期分享技术干货

oracle如何保证数据一致性和避免脏读的更多相关文章

  1. MySQL 是怎么保证数据一致性的(转载)

    在<写数据库同时发mq消息事务一致性的一种解决方案>一文的方案中把分布式事务巧妙转成了数据库事务.我们都知道关系型数据库事务能保证数据一致性,那数据库到底是怎么设计事务这一特性的呢? 一. ...

  2. ZooKeeper 如何保证数据一致性?

    在分布式场景中,ZooKeeper 的应用非常广泛,比如数据发布和订阅.命名服务.配置中心.注册中心.分布式锁等. 在分布式场景中,ZooKeeper 的应用非常广泛,比如数据发布和订阅.命名服务.配 ...

  3. 【面试普通人VS高手系列】Redis和Mysql如何保证数据一致性

    今天分享一道一线互联网公司高频面试题. "Redis和Mysql如何保证数据一致性". 这个问题难倒了不少工作5年以上的程序员,难的不是问题本身,而是解决这个问题的思维模式. 下面 ...

  4. Dynamo分布式系统——「RWN」协议解决多备份数据如何读写来保证数据一致性,而「向量时钟」来保证当读取到多个备份数据的时候,如何判断哪些数据是最新的这种情况

    转自:http://blog.jqian.net/post/dynamo.html Dynamo是Amazon开发的一款高可用的分布式KV系统,已经在Amazon商店的后端存储有很成熟的应用.它的特点 ...

  5. oracle如何保证读一致性 第二弹

    Oracle之数据库一致性读的原理 在Oracle数据库中,undo主要有三大作用:提供一致性读(Consistent Read).回滚事务(Rollback Transaction)以及实例恢复(I ...

  6. oracle如何保证读一致性 第一弹

    oracle保证读一致性原理   1:undo segment的概念                   当数据库进行修改的时候,需要把保存到以前的old的数据保存到一个地方,然后进行修改,用于保存o ...

  7. ZK集群如何保证数据一致性源码阅读

    什么是数据一致性? 只有当服务端的ZK存在多台时,才会出现数据一致性的问题, 服务端存在多台服务器,他们被划分成了不同的角色,只有一台Leader,多台Follower和多台Observer, 他们中 ...

  8. MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  9. 通俗理解ZooKeeper是如何保证数据一致性的

    https://blog.csdn.net/liuhaiabc/article/details/70771322 https://blog.csdn.net/zhaoyangjian724/artic ...

随机推荐

  1. 微信小程序“一劳永逸”的接口封装

    前言 最近都在研究小程序了,我可以的! 需求 之前都是用vue来开发项目的,接口模块我特意封装了一下.感觉也可以记录一下 小程序的接口虽说简单,但是重复调用那么多,显得不专业(一本正经的胡说八道) 还 ...

  2. javascript中对一个对象数组按照对象某个属性进行排序

    需求:对timelist排序 安装keys . 分析:timelist 是个数组对象,里面包含属性 keys,val.这里借助数组sort方法 传入function <script> // ...

  3. C#中使用typeof关键字和GetType()获取类的内部结构(反射机制)

    一.问题描述 java有反射机制,C#也有反射机制,在C#中typeof关键字用于获取类型的System.Type对象,该对象的GetMethods()方法可以得到类型中定义的方法对象的计集合,调用方 ...

  4. Mysql sql_mode设置 timestamp default 0000-00-00 00:00:00 创建表失败处理

    往数据库里创建新表的时候报错: [Err] 1067 - Invalid default value for 'updateTime' DROP TABLE IF EXISTS `passwd_res ...

  5. DNGuard HVM Unpacker(3.71 trial support and x64 fixed)

    DNGuard HVM Unpacker(3.71 trial support and x64 fixed) Gr8 news. Finally got the x64 crash fixed. DN ...

  6. curl获得cookie数据<转>

    CURL *curl; CURLcode res; struct curl_slist *headers = NULL; curl_global_init(CURL_GLOBAL_ALL); curl ...

  7. Wamp 本地访问特别慢,原因在这

      Wamp 本地访问特别慢.打开空的页面都要400ms,彻底疯了     什么localhost改为127.0.0.1 什么 清理日志缓存,都不好使, 重点在Xdebug,安装了Xdebug之后变慢 ...

  8. Oracle 查询表注释以及字段注释

    Oracle 查询表注释以及字段注释 --表字段信息 select * from all_tab_columns a where a.TABLE_NAME='T_X27_USER'; --表注释信息 ...

  9. AndoridSQLite数据库开发基础教程(7)

    AndoridSQLite数据库开发基础教程(7) 为空表添加数据 开发者可以单击Data按钮,看到Students表中是没有数据的,创建好的Students表是一个空表.如图1.15所示.如果开发者 ...

  10. ISO/IEC 9899:2011 条款6.4——词法元素

    6.4 词法元素 1.token(标记): keyword(关键字) identifier(标识符) constant(常量) string-literal(字符串字面量) punctuator(标点 ...