学习笔记-事务与回滚段

1.常用事务操作
Oracle相关事务的SQL操作主要包含
insert:数据插入
update:数据更新
delete:数据删除
merge:合并操作
select …for update:锁定选择数据
2.事务的ACID原则:
1)A:原子性—事务是原子级的、不可分割的有机体,这意味着,事务过程修改是不能分割的,即过程修改或者全部执行成功,或者全部执行失败回滚,不能存在部分成功部分失败的场景;
2)C:一致性—与事务相关的数据获取是一致性的,即事务的过程修改不影响其他事务获取一致性状态的版本;
3)I:隔离性—事务间的数据更改都是隔离且透明的,即不同事务的修改过程都是不能被互相查询获取的;
4)D:持久性—提交成功的事务数据修改是永久的,这个特性是Oracle日志触发写特性决定的,即当事务提交,日志信息就被写入日志文件,实现永久存储,保证事务的修改不会丢失。

注:Oracle默认的事务隔离级别是提交可读(READ_COMMITED),也就是说事务在修改后,没有提交,其他的事务是无法查看其修改的数据的,只有该事务提交成功,最终版本的数据才可见。

3.Oracle事务与回滚段运行机制:
1)事务开始的时候,系统会在回滚段头的事务表(Undo segment header)中分配一个事务槽(TX Slot);
2)同时,事务影响的数据块头(Data Block Header)打开与事务对应的ITL,该ITL包含了事务的UBA信息,用于指向数据块前镜像所在的Undo Block地址以及Undo Record地址(Rec#);
3)在修改数据前将数据块前镜像记录到Undo Block中,以Undo Record的方式进行存储。
4)修改事务影响锁定的数据行(lb状态)
5)事务结束(commit/rollback)

我们可以通过以下案例,更加通俗的理解事务与回滚段的运行机制:
1)构建表以及案例:
SQL> select * from wangxin.t;
在这里插入图片描述
2)对数据表进行update操作:

SQL> update t set id=3 where name=‘lanshan’;

3)查看并确认我们准备操作的对象的object_id
select object_id from dba_objects where object_name=‘T’;
在这里插入图片描述
4)查看当前正在执行的事务:
SQL> select XIDUSN,XIDSLOT,XIDSQN,UBAFIL,UBABLK,UBASQN,UBAREC,STATUS from v$transaction
在这里插入图片描述
这里,可以得到的信息有:
1.事务的usn为1;
2.事务的slot槽为27;
3.事务使用的undo file文件号为11;
4.事务使用的undo block为8879个块;
5.事务使用的undo record为4;

接下来,我们将分别对当前事务使用的undo头、undo块、数据块进行dump来验证这些信息。

5)查找当前事务使用的回滚段使用情况:

SQL> select usn,latch,rssize,xacts,status,curblk from v$rollstat;
在这里插入图片描述

这里,我们可以通过XACTS字段知道,当值为1时,表名usn为1的回滚段有事务正在进行;
6)通过usn确定该回滚段的名字:
SQL> select usn,name from v$rollname;
在这里插入图片描述

这里,可以知道,当前被使用的回滚段名字叫:_SYSSMU1_1399957073$

7)我们通过xbh和dba_segments,来查看当前对象(T表)的块头信息情况:
SQL> select ex.segment_name,
2 bh.file#,
3 bh.DBARFIL,
4 bh.dbablk,
5 bh.CLASS,
6 bh.STATE,
7 ex.BLOCK_ID,
8 ex.blocks
9 from x$bh bh, dba_extents ex
10 where bh.DBARFIL = ex.RELATIVE_FNO
11 and ex.BLOCK_ID < bh.DBABLK
12 AND ex.block_id + ex.blocks > bh.dbablk
13 and ex.owner = ‘WANGXIN’
14 and ex.segment_name = ‘T’ order by bh.dbablk;
在这里插入图片描述
这里,我们可以知道以下信息:
1.由于class为4,所以我们可以知道file#=12,block=130的数据块存储的是T表的段头信息;
2.由于class为1,且block最小,所以我们可以知道file#=12,block=131存储的是T表的初始数据;

8)查看T表中数据块的状态信息:
SQL> select file#,block#,class#,status,objd,ts# from v$bh where objd=73335 order by block#;
在这里插入图片描述
接下来,我们对相关的回滚段信息、数据块信息、undo块信息进行dump,验证其中的关系以及在进行事务操作时候的运行机制:

9)对刚才查询的回滚段头信息进行dump操作

SQL> alter system dump undo header ‘_SYSSMU1_1399957073$’;
在这里插入图片描述
在这里插入图片描述

通过这段dump信息,我们可以从其事务回滚段表中得到以下信息:
1.state=10,表示当前事务正在进行;
2.index=0x1b,换算成10进制为27,这里和通过v t r a n s a c t i o n 查 询 的 X I D S L O T 是 一 致 的 ; 3. d b a = 0 x 024022 a f , 进 行 换 算 后 , 则 表 示 的 u n d o f i l e = 11 , u n d o b l o c k = 8879 , 这 里 和 通 过 v transaction查询的XIDSLOT是一致的; 3.dba=0x024022af,进行换算后,则表示的undo file=11,undo block=8879,这里和通过v transactionXIDSLOT3.dba=0x024022af,undofile=11undoblock=8879vtransaction查询的UBAFILE和UBABLOCK一致;
因此,我们可以知道,在事务使用的回滚段中,保存了该事务的undo指向信息(该事务使用了undo的哪一个文件,哪一个块)。

10)对当前对象的数据初始存储块进行dump,查看其中保存的信息
SQL> alter system dump datafile 12 block 131;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从这里,我们可以得到以下信息:
1.nrow=5,表明block中有5行数据。
2.可以从block_row_dump中看到,当前被itl=0x02锁定的行,为tab 0, row 2, @0x1f64;
3.此时的数据通过转换,可以得到的数据即为:3,lanshan,26,而这里存储的数据,我们可以发现是我们update之后的新数据。

11)对事务指定的undo块进行dump:
SQL> alter system dump datafile 11 block 8879;
在这里插入图片描述
在这里插入图片描述
从这里,我们可以得到以下信息:
1.Rec #0x4的slt为0x1b,和我们在v$transaction、回滚段头中的slt为27一致;
2.objn为73335,即我们update的对象,表T;
3.该条record中记录的数据信息翻译:col 0----第一列数据(从0开始计数),即为id那一列,我们通过表结构也可以确定第一列为id;数据为c1 03-----即数据为2,这是我们的前镜像数据(update之前的旧数据);

综上所述,
当我们在进行update事务操作的时候,最新的数据会被记录在实际的数据块中,但由于我们没有提交。
其旧数据此时会被存放在undo块中(这里我们称为前镜像数据)。
而此时,其他用户获取该数据,将从这个undo块中获取。
且我们通过对事务的查询,可以确认到就数据存放的undo块信息。

4.Oracle的回滚段
Oracle的回滚段(Rollback segment)的主要作用有:重构一致性读(CR读),事务锁定,块清除(cleanout)。

1)回滚段一致性读

在事务没有提交的情况下,当用户读取到事务影响的block,将会发现该block的ITL是处于open状态的;
通过查询回滚段头事务表(ITL)确认事务是活动状态的,即state=10。那么此时用户的服务进程就会利用回滚段信息进行事务回滚,重构原始状态的block镜像,该block镜像被称为block的一致性读副本;
CR Copy重构的过程中,首先会克隆当前的Data Block,然后应用Undo Block中的Undo Record将克隆Data Block回滚到事务更改前的一致性版本(commit SCN)。

所以,重构CR block涉及到的有data block,rollback segment,undo(block/record),在重构过程中,必须保证这些对象无异常。

2)回滚段事务锁
事务锁主要用于保护数据的完整性,隔离其他事务对本事务的数据修改影响(事务的隔离性)。

如果有事务在更改某行数据时,但事务并没有提交。那么当有其他的会话也需要更改这行数据的时候,数据库将会进行以下操作:
1.后发起的session的服务进程首先会检查该block的ITL处于Open状态,然后通过ITL确认回滚段头事务表中的事务储于活动状态(state=10);
2.活动状态事务的ITL说明该行数据被事务锁定,因此其他session只有等到当前事务结束后,才能锁定并更改这行数据。

所以,当事务锁定的时候,回滚段头出现异常,那么可能就会影响事务的锁定。

3)回滚段与块清除

1.当事务提交以后,事务影响的数据块更改将长期有效(事务的持久性)。于此同时,系统会对这些数据块的事务槽标志(ITL)进行清除操作,然后将这些数据块作为新的数据块基础版本。
2.而此时,当用户请求更改这些数据块的时候,就不再需要重构CR Copy了,而是可以直接将这些数据块作为新的及版本进行事务操作。系统对这些数据块的事务槽标识清除的过程就是块清除(block cleanout)

快速块清除:
如果一个事务修改的数据块不超过10%的Buffer Cache容量,那么当事务提交的时候,Oracle会根据modified block list中的记录定位到被修改的数据块,进行
快速块清除(fast block cleanout);

延迟块清除:
如果事务提交完成,但事务修改的Block事务槽(ITL)没有来的及关闭,那么下一次访问该block的时候,会进行延迟块清除;
当单个事务更改的block buffer数量超过buffer cache的10%容量,那么系统会根据’modified block list’将对超过部分做延迟块清除;
当事务在提交前,修改过的block buffer已经被写到磁盘的时候,也会进行延迟块清除。

那么事务提交和延迟块清除之间的运行机制是如何:

当事务提交完成后,系统将回滚段头事务表的事务状态更新为非活动状态(state=9);
Data Block事务槽(ITL)没有立即被清除,将持续打开一段时间;
当下一次访问该block的时候,新的会话会发现这个block的ITL是打开状态,接着检查回滚段头事务表,来确认事务为非活动状态(commit)。
那么系统就会关闭该block的ITL,而这个过程就是延迟块清除。

另外,如果在查询回滚段事务表前回滚段头不可用,那么系统将检查数据字典表undo$确认该事务已经提交,从而关闭Block的事务槽,实现延迟块清除。

5.Oracle事务恢复

在事务进行过程中,如果被异常中断,则需要通过事务恢复保证数据一致性。

事务恢复可以分为3类:
1)SQL类:rollback,有server process实现事务恢复;
2)进程类:session运行事务异常崩溃的时候,由pmon进程进行事务恢复;
3)DB类:当实例或者整个数据库在进行事务时,被异常关闭。此时,在实例或者数据库恢复后,将有smon进程进行恢复。

rollback下的事务恢复,其主要步骤如下:
1)当发出rollback指令后,系统首先扫描回滚段头事务表获取ITL信息;
2)通过ITL精确定位到事务相关的undo records,然后逐级应用、回滚;
3)当rollback执行成功后,数据块更改都回滚完毕,同时数据块事务槽(ITL)也被清除成功(Block Cleanout);
4)Rollback操作会产生新的redo来记录回滚操作,也就是说,回滚操作也会被记录在redo中。

注:rollback执行成功后,Data Block上的ITL清除是快速块清除。

进程崩溃时的事务恢复,其主要步骤如下:
1)当事务正在进行的时候,如果会话异常崩溃,那么系统首先会将探测到的崩溃进程标记为’Dead’状态;
2)然后进行中止事务操作以及清除’Dead’进程操作;
3)由PMON进程完成后续的资源清除工作。

我们可以在初始化参数文件中,设置事件对事务恢复相关事件进行跟踪:
event 10012:跟踪崩溃事务
event 10013:跟踪数据库启动时的事务恢复
event 10015:跟踪回滚段头信息
event 10246:跟踪PMON进程活动
event 10050:跟踪SMON进程活动

当进程崩溃的事务恢复,从pmon的追踪文件中可以发现,其恢复主要分为步骤:
1)进程崩溃后,系统首先将进程标记为’dead’状态;
2)接着系统会删除进程资源;
3)然后系统终止事务(ABORT TRANSACTION)
4)PMON进程清除其他系统资源
通过这些,将事务恢复到rollback的一致性状态。

实例崩溃下的事务恢复:

在事务提交前,当出现异常情况导致数据库实例crash的时候,数据库可能不能及时回滚事务,故只能等到下一次
数据库启动时,先进行crash recovery,然后按照先前滚,后回滚的方式进行事务恢复。

先前滚,后回滚是指:
1)首先数据库进行rollback forward操作,恢复到redo checkpoint恢复点,这个点包含了未来得及提交的数据块更改;
2)然后进行rollback操作,应用undo record回到数据块一致性状态版本。

从日志中看,可以看到系统会首先进行crash recovery,然后自动完成事务恢复,将事务恢复到一致性状态。

6.数据库异常关闭下的事务恢复:
数据库在事务进行的过程中,遭遇异常关闭,则其恢复主要为以下步骤:
1)系统回滚段(system)回滚段中的活动事务会立即回滚;
2)非系统回滚段中的活动事务会被标记为’DEAD’;
3)当数据库正常打开一段时间后,SMON进程才会通过扫描回滚段头进行’DEAD’事务的恢复操作,延迟恢复策略是为了加快数据库重新打开的速度而采取的优化措施:
在Oracle数据库异常关闭的情况下,应当经可能快的重新打开数据库,及时恢复业务的正常运行;
数据库重新打开后,新事物需要更新为’DEAD’事务锁住的数据行时,发起新事物的服务进程就会自动回滚’DEAD’事务,而不必等待一段时间的smon事务恢复。

而当数据库异常关闭后,在重启过程中,回滚段头出现异常而不能被读取,那么数据库就不能正常的打开,必须使用特殊恢复进行数据库恢复。

回滚段特殊恢复:

当回滚段出现异常的时候,将会影响数据库CR重构,事务锁定,块清除等回滚段紧密相关的数据库功能,甚至也可能导致数据库无法正常启动。
因此,回滚段出现异常后,需要对回滚段进行特殊回恢复,特殊恢复主要遵循以下几个原则:
1)介质恢复(Media recovery)是首要的恢复方式,能保证数据恢复的一致性和完整性;
2)当介质恢复不能解决问题的时候,可以考虑使用隐藏参数来进行特殊恢复;
3)特殊恢复作为最后的恢复手段,需要对特殊恢复带来的风险、特殊恢复时间,以及恢复失败回退机制等要点进行综合评估,尽可能减少数据丢失。

Oracle回滚段特殊恢复隐含参数:
1)_offline_rollback_segments
2)_corrupted_rollback_segments
在这里插入图片描述

_offline_rollback_segments在参数文件中可以表示为:

*._offline_rollback_segments=(v1,v2,v3)
其中,v1,v2,v3表示需要offline的回滚段

_corrupted_rollback_segments在参数文件中可以表示为:

*.rollback_segments=(v1,v2,v3)
*._corrupted_rollback_segments=(v4)
其中v1,v2,v3表示需要online使用的回滚段,v4表示强制异常的回滚段。

7.Oracle回滚段特殊恢复场景
1)回滚段隐藏参数与数据库打开:

在数据库打开的过程中,处于_offline_rollback_segments/_corrupted_rollback_segments参数列表中的回滚段有以下特点:
回滚段不会检查回滚段头事务表信息,同时,回滚段头的活跃事务也不会被标记为dead或者rollback的状态;
回滚段处于离线状态;
回滚段不能分配给新的事务使用。

2)回滚段隐藏参数与一致性读和块清除:

隐藏参数_offline_rollback_segments,当事务槽处于开启状态(ITL Open)的BLOCK与_offline_rollback_segments参数表上的回滚段相关时,数据库在重新打开过程中需要检查_offline_rollback_segments列表上的回滚段头事务信息表,获取事务状态:
当事务提交(Inactive)时候,块清除;
当事务未提交(active)时候,其他的session读取这个block时,则需要应用undo record来重构CR Copy。
所以,需要注意的是:尽管_offline_rollback_segments中的回滚段已经offline了,但是Oracle仍然会读取这些回滚段来检查事务状态,在回滚段Online以后,
应用Undo record进行回滚。如果这些回滚段中存在坏块,那么Oracle回滚操作就会失败。

隐藏参数_corrupted_rollback_segments,当事务槽处于开启状态(ITL Open)的BLOCK与_corrupted_rollback_segments参数列表上的回滚段相关时,数据库在重新打开过程中则不会读取_corrupted_rollback_segments列表中的回滚段事务表信息,这样就可以通过这个特性越过系统对回滚段的检查来尝试启动数据库。

如果active事务没有提交,将会出现逻辑异常错误,可以使用参数_corrupted_rollback_segments来越过系统检查,尝试启动数据库;
当_corrupted_rollback_segments列表中的回滚段被删除后,系统将’DEAD’状态的事务当作已经被提交,进行延迟块清除。

但是,如果在ITL被清除前,标记为corrupted状态的回滚段被重用(从_corrupted_rllback_segments参数列表中移除),这时候就需要回滚之前已经提交的事务,但会导致
BLOCK的逻辑异常。所以,建议在使用隐藏参数_corrupted_rollback_segments后,将参数列表中的回滚段删除。

3)回滚段隐藏参数与回滚段删除:

在一般的情况下,回滚段时不能被删除的,这是因为回滚段中包含了ACTIVE事务的信息,保存了事务恢复的回滚记录。为了保证数据的一致性,Oracle不允许
删除有活动事务的回滚段。

但是,在特殊情况下,将存在活动事务的回滚段添加到_corrupted_rollback_segments列表中,就可以忽略回滚段保护机制。也就是说,在数据库启动过程中,
处于_corrupted_rollback_segments列表中包含有活动事务的回滚段可以被删除。方法就是将给该回滚段添加到_corrupted_rollback_segments列表中。

案例如下:
直接删除,会报错,不允许删除
SQL> drop rollback segment “_SYSSMU9_705758041 " ; d r o p r o l l b a c k s e g m e n t " S Y S S M U 9 7 05758041 "; drop rollback segment "_SYSSMU9_705758041 ";droprollbacksegment"SYSSMU9705758041
*
ERROR at line 1:
ORA-30025: DROP segment ‘_SYSSMU9_705758041$’ (in undo tablespace) not allowed

加入隐含参数_corrupted_rollback_segments列表中,重启数据库,进行删除。

alter system set “_corrupted_rollback_segments”=’_SYSSMU9_705758041 ′ s c o p e = s p f i l e ; 重 启 数 据 库 : S Q L > ; 1 ∗ s e l e c t a . u s n , a . n a m e , b . x a c t s , s t a t u s f r o m v ' scope=spfile; 重启数据库: SQL> ; 1* select a.usn,a.name,b.xacts,status from v scope=spfile;SQL>;1selecta.usn,a.name,b.xacts,statusfromvrollname a,v$rollstat b where a.usn=b.usn
SQL> /

在这里插入图片描述

此时可以看到回滚段中已经没有usn=9的回滚段了。

删除回滚段:

SQL> drop rollback segment “_SYSSMU9_705758041$”;
Rollback segment dropped.

此时,删除成功。

将usn=9的回滚段移出_corrupted_rollback_segments表
alter system set _corrupted_rollback_segments=’’ scope=spfile;

8.回滚段特殊恢复实战:

当存在活动事务的回滚段表空间出现异常的时候,可以通过以下步骤进行特殊恢复:
1)创建新的初始化参数;
2)修改新的初始化参数,修改参数内容包括:undo_tablespace、undo_management、_allow_resetlogs_corruption、_corrupted_rollback_segments
3)用修改后的参数文件启动数据库;
4)在启动成功的数据库中创建新的undo表空间;
5)删除异常undo表空间;
6)关闭数据库;
7)修改初始化参数文件,重新配置回滚段表空间,正常启动数据库,重建spfile。

案例:
1)show parameter pfile;
在这里插入图片描述

2)create pfile=’/tmp/pfile123’ from spfile;
3)vi /tmp/pfile123
在这里插入图片描述
4)startup restrict pfile=’/tmp/pfile123’;
SQL> select a.usn,a.name,b.xacts,status from v r o l l n a m e a , v rollname a,v rollnamea,vrollstat b where a.usn=b.usn;
在这里插入图片描述

5)create undo tablespace undotbs2 datafile ‘+DATA’ size 2G autoextend off;

6)alter tablespace undotbs1 offline;

drop tablespace undotbs1 including contents and datafiles;

7)shutdown immediate;

8)vi /tmp/pfile123
undo_tablespace=‘UNDOTBS2’
undo_management=‘AUTO’
删除
*._allow_resetlogs_corruption=true
*._corrupted_rollback_segments=(_SYSSMU1_1399957073 , S Y S S M U 6 1 939243974 ,_SYSSMU6_1939243974 ,SYSSMU61939243974,_SYSSMU8_100119489$)

9)启动数据库,并重建spfile
startup pfile=’/tmp/pfile123’;
alter system set spfile=’+DATA/cdbwx/parameterfile/spfile.273.1034670121’;
create spfile from pfile=’/tmp/pfile123’;

vi /u01/app/oracle/product/12.2.0/dbhome_1/dbs/initcdbwx.ora
spfile=’+DATA/cdbwx/parameterfile/spfile.273.1034670503’

10)重启数据库
startup

SQL> show parameter undo
在这里插入图片描述

SQL> select usn,name from v$rollname;
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wx370092877/article/details/104786483