热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

OCP知识点讲解之Undo的回滚和提交

一、回滚段块的使用总结:1.1Seq序列值:步骤1:在每个回滚块的块头,有一个SEQ值,当事务延伸到新区时,新区的SEQ是上一区SEQ加1。如:www.2cto.com步骤2:步骤3:事务B提交步骤4:事务A发布新的更新声明,它...SyntaxHighlighter.all()

一、回滚段块的使用总结:
1.1 Seq序列值:
步骤1:
在每个回滚块的块头,有一个SEQ值,当事务延伸到新区时,新区的SEQ是上一区SEQ加1。如:
www.2cto.com
步骤2:
步骤3:事务B提交
 
步骤4:事务A发布新的更新声明,它所占回滚块开始增长:
事务A增长,占用83、84、85、86、87块,但到达88块时,发现88、89块的序列值也是10,并不小于自身的序列值,事务A跳过88、89块,90块的序列值小于10,事务A占用90号块。
 
步骤5:
事务A继续增长,当事务A延伸至下一区时,下一区块的序列值为11:
结论:只有当事务为块分配的序列值大于块本身的序列值时,事务才可占用此块。上例中事务 B已提交的块,只有当A事务提交后,另有其他事务从末尾区延伸到区0时,才会被占用。
www.2cto.com
1.2 区的膨胀(Extend):
事务A不断增长,已经占满了区0。事务A又请求新的回滚块,由于事务Z从区1开始,因此区1有“活动事务”,此时Oracle再分配一个新区作为区1,老的区1变为区2,如下:
就算老区1后还有空闲的老区2,此处还是会分配新区1的。
 
二、回滚和提交:
2.1 回滚:
如果某一事务回滚,其操作步骤是:
1.在事务表中取出它的DBA列,此DBA是事务回滚链末端回滚块的DBA
2.通过此DBA找到回滚链的末端
3.沿回滚链从尾向前,依次取出回滚记录所对应的原表的DBA、行号、列号,以及其前映像信息,
4.将前映像信息重新写入原表相应的DBA中
从上面的步骤可以看到,回滚的顺序,与你操作的顺序正相反,如果你删除了1,2,3,4,5条记录,然后回滚,Oracle从后向前,依次插入5,4,3,2,1条记录。
 
2.2 提交:
事务提交后,事务表上的事务状态列被置为非活动。此事务不可再回滚,因为回滚先要到事务表查出事务回滚链的末尾块。
但是,提交后,虽然事务表上已经标明此事务是非活动事务,不过回滚块中的信息还在,虽然不能回滚,但这些回滚块中的信息在被覆盖前,仍是可以被读取的。
关于这一点,我们可以找个事务,提交后再DUMP它占用的回滚块,根据回滚段循环使用原则,这些回滚记录到下一轮循环时才会被覆盖。
 
三、自己动手构造CR块:
3.1 查询魔术:
步骤1:在会话17中发布如下声明:
17> var x refcursor
17> exec open :x for select substr(c,1,5),id from t8;
PL/SQL 过程已成功完成。
 
步骤2:在会话13删除T8的所有记录且提交:
13> delete t8 ;
已删除 10 行。
13> commit;
提交完成。
 
步骤3:在会话17中输出游标X的所有行:
17> print x
SUBSTR(C,1 ID
---------- ----------
g 7
h 8
i 9
J 10
AA1
B 2
C 3
D 4
E 5
f 6
已选择10行。
我们在会话13中已删除且已提交,但在会话17中还是显示出了T8中的所有行,这是为什么呢?
 
1) 在步骤1打开游标,但此时并没有执行、执取,在会话17的PGA中,将会开辟一块内存存贮此游标。在游标的相关信息中,有一条就是游标打开是的SCN,假若此时的SCN是1000。
 
2) 在步骤2中对表T8进行了操作,并提交。Oracle每个数据块的头部,都记有此块当前的SCN值,此SCN值随着对块的更新而变化。假如,我们在步骤2更新T8表时,SCN是1200,这个值将被记入块头部的SCN值。
 
3) 在步骤3我们发布Print x声明,此声明将完成执行、抓取等步骤。在从T8表的相关块中抓取行时,Oracle会将打开游标时的SCN和块本身的SCN相比较,如果发现后者大于前者,证明打开游标是在更新表之前进行的,Oracle将会在回滚段中寻找小于游标SCN的信息,构造一个在打开游标之前的块,这就是CR块了。如果回滚段中的T8表的信息已经被覆盖,将会报告一个ORA-01555 快照太老错误。
执行时间过长的查询,有时也会报出这个错误。
 
3.2 SCN:
SCN就是Oracle内部的一个记时机值,也就是Oracle的内部时钟。在9i之后,我们可以通过如下的方式获得当前的SCN号:
scott@MYTWO>
select scn,to_char(scn,’xxxxxxx’) from (select dbms_flashback.get_system_change_number
SCN from dual);
SCN
----------
8727805
在几乎所有的地方,你都能见到SCN。在事务表、回滚块中的回滚记录、数据块、日志文件等等,我们上面曾提到过,在游标中,记录的也有游标打开时的SCN。
 
3.3 构造CR块:
Oracle会在三种情况下去读回滚段构造CR块:
1.只要数据块上有锁,Oracle将会构造CR块。
2.游标的SCN小于块的SCN,证明块在游标打开之后又被修改过了,这就要去构造CR块。
3.闪回查询中,要求的SCN小于块的SCN,也要去构造CR块。
 
步骤1:先观察表T8的行分布情况:
ROWIDBLOCK# CID
------------------ ---------- ---------- ----------
AAAB3LAAFAAAf/mAAA 131046 a 1
AAAB3LAAFAAAf/mAAB 131046 b 2
AAAB3LAAFAAAf/mAAC 131046 c 3
AAAB3LAAFAAAf/nAAA 131047 d 4
AAAB3LAAFAAAf/nAAB 131047 e 5
AAAB3LAAFAAAf/nAAC 131047 f 6
AAAB3LAAFAAAf/oAAA 131048 g 7
AAAB3LAAFAAAf/oAAB 131048 h 8
AAAB3LAAFAAAf/oAAC 131048 i 9
AAAB3LAAFAAAf/pAAA 131049 j10
 
步骤2:发布更新命令
13> update t8 set c=upper(c) where id<=2;
已更新2行。
13> commit;
提交完成。
...
10> update t8 set c=&#39;az&#39; where id=1;
已更新 1 行。
10> update t8 set c=&#39;by&#39; where id=2;
已更新 1 行。
此时的SCN是
18> select dbms_flashback.get_system_change_number SCN from dual;
SCN
----------
8729612
总结一下:
行1的变化a->A->A1 A2 B2->aa1->aaa1aaaa1->aaaaa10->az
行2的变化b->B->B2->bb2->bbb2bbbb2->bbbbb10->by
下面开始构造CR块,首先说一下末提交时CR块的构造:
 
步骤3:末提交时CR块的构造:
接着上面的修改,如果我们在会话16发布查询T8表的声明:
16> select * from t8 where id<=3;
由最后一次修改没有提交,假如此时有其他会话访问行1或行2,就回发生回滚操作,从而构造一个CR块。让我们自己来回滚一下,感受一下Oracle的回滚操作到底做了什么:
首先DUMP块131046:
alter system dump datafile 5 block 131046;
在事务的头部,有一块这样的结构:
Itl XidUba FlagLckScn/Fsc
0x01 0x0018.008.0000001a0x03800073.000e.02----2fsc 0x0000.00000000
0x02 0x0019.007.000000200x03800053.0037.01C---0scn 0x0000.008533f6
它被叫做ITL,Interested Transaction List,相关事务列表。此表中每一行,按Oracle惯用的说法,又叫一个槽,SLOT。当有事务修改此块中的数据时,或者说此块中有事务发生时,就在ITL中占用一个槽。下面我们了解一下ITL中的信息。
第一列,ITL编号,共有两个,分别是0x01,0x02,随着此块中事务的增多,槽数量也会增多。
第二列,Xid,事务Xid编号,Xid共分三段,我们在上文中已经讲过,回滚段编号.槽号.序列号。我们来看0x01事务,它占用24号回滚段的第8个槽,此槽的序列号是26,即24.8.26。
第三列,UBA,回滚块地址。也分三段,分别是回滚块地址,回滚块序列号,回滚链末记录号(即irb信息)。此处0x01事务占用14号文件,115号回滚块,块序列号是14,回滚链的末记录在115的第2条记录处。
第四列,Flah,标志,共有四位,四位都是“----”,事务末提交,第一位是C,“C---”,事务已提交。
第五列,Lck,事务所修改的行的数量。这些行,都算是被事务锁住的行。
第六列,SCN/Fsc,是事务的SCN信息。0x01事务尚末提交,故此列为0。
这个新生成的块,块的编号仍是131046,在内存中,它的HASH位置会和原来的131046处于同一HASH Cache Buffer Chain。它就是131046的CR块。CR块的构造到现在还没有完成,我们用前像映像行值替换了当前的行值,我们最后一步所做的更新并仅仅修改了行的值,上面我们讲到,每个块头有一个ITL,它初始有两个槽,每个末提交的事务,将占用一个槽,可以随事务增多而扩充。如果事务已提交,它占用的槽会被下一个事务覆盖。因此,我们最后在会话10中做的更新,将覆盖131046的一个已提事务的ITL槽,这个被覆盖的ITL槽被记进事务回滚链头部块中,如下所示:
op: Litl: xid:0x001a.010.00000011 uba: 0x03800085.000e.01
flg: C---lkc:0 scn: 0x0000.00853185
我们应该用它替换131046中当前的0x01槽:
Itl XidUba FlagLckScn/Fsc
0x01 0x0018.008.0000001a0x03800073.000e.02----2fsc 0x0000.00000000
0x02 0x0019.007.000000200x03800053.0037.01C---0scn 0x0000.008533f6
替换为:
Itl XidUba FlagLckScn/Fsc
0x01 0x001a.010.000000110x03800085.000e.01C---0fsc 0x0000.00853185
0x02 0x0019.007.000000200x03800053.0037.01C---0scn 0x0000.008533f6 www.2cto.com
好了,到现在,我们终于构造了一个131046的CR块:
Itl XidUba FlagLckScn/Fsc
0x01 0x001a.010.000000110x03800085.000e.01C---0fsc 0x0000.00853185
0x02 0x0019.007.000000200x03800053.0037.01C---0scn 0x0000.008533f6
 
Slot 0(行1):61 61 61 61 61 31 30 (“aaaaa10”) 相关末提交事务0x1
Slot 1(行2):62 62 62 62 62 31 30 (“bbbbb10”) 相关末提交事务0x1
Slot 2(行3):63 (“c”) 无相关事务
现在,131046的CR块中的ITL中,所有事务都已提交,我们的回滚是否可以到此为止呢?
还不行,Oracle还要对比一下查询游标打开时的SCN,如果大于上面CR块中ITL的最大提交SCN:8533f6,证明查询发生在事务结束之后,查询时的SCN大致是:
18> select scn,to_char(scn,&#39;xxxxxxxxxx&#39;) from (select dbms_flashback.get_system_change_number
SCN from dual);
SCN TO_CHAR(SCN
---------- -----------
87346498547b9
后于CR块ITL中最大提交SCN,好,到此为止,回滚结束。如果游标的SCN前于ITL中最大提交SCN,Oracle仍要继续回滚。
www.2cto.com
关于CR块的构造过程,我们就讲到这里。在此过程中,我们一直很少用到事务表,在这里,ITL是重要的,我们靠它向前回滚。但在构造CR块的开始,Oracle仍然要读事务表。这一点从X$BH中的“接触点”可以看出来。每发布一次产生CR块的查询,回滚段头的TCH列都有增加。ITL在每个数据块的块头,它是针对块的,而事务表则是针对事务的。
在Rollback时,Oracle一定要去读取事务表,因为一个事务可能涉及很多回滚记录、很多回滚块,这些回滚记录被回滚链串起来,而只有在事务表中,才能找到回滚链尾记录的UBA。因此,回滚一定要从回滚链末尾开始。

推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了在SQL中查询分组后每组行数的统计方法。通过使用count()函数和GROUP BY子句可以统计每组的行数,但是如何统计所有组的行数呢?本文提供了一种实现方法,并给出了相应的SQL查询语句。 ... [详细]
  • 在数据分析工作中,我们通常会遇到这样的问题,一个业务部门由若干业务组构成,需要筛选出每个业务组里业绩前N名的业务员。这其实是一个分组排序的 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 本文介绍了adg架构设置在企业数据治理中的应用。随着信息技术的发展,企业IT系统的快速发展使得数据成为企业业务增长的新动力,但同时也带来了数据冗余、数据难发现、效率低下、资源消耗等问题。本文讨论了企业面临的几类尖锐问题,并提出了解决方案,包括确保库表结构与系统测试版本一致、避免数据冗余、快速定位问题等。此外,本文还探讨了adg架构在大版本升级、上云服务和微服务治理方面的应用。通过本文的介绍,读者可以了解到adg架构设置的重要性及其在企业数据治理中的应用。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
author-avatar
我是小钞票
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有