27、undo_1_1(事务)
undo表空间
图解:
oracle数据库件建完库以后,自己就会生成一个undo表空间(数据文件组成),里面有好多的block;undo表空间里面会默认生成一堆undo段,段的名字都是以下划线开头的,undo表空间默认会生成10个undo段,同时在system表空间里面也会生成一个undo段
图解:
undo段也有段头,也被分配extent,从物理上来讲,也是由物理上连续的block组成
什么时候使用undo段呢(undo的作用)?
比如现在要修改数据库里面的一行数据,将1该为2,oracle就会保留1,oracle就会把这个1写到undo表空间里面其中的一个undo段里面去,然后将1该为2之后,后悔了,就使用rollback命令,把原来的1从undo段里面取出来,然后覆盖修改之后的2,就改回原来的1了
undo段
undo表空间里面undo段的特点:
1、有名字
2、会被分配一些extent(区);
3、这些undo段是oracle自己去使用(t1表和索引段是我们在做inster、update、delete的时候去使用,而undo段是oracle自己去使用);
4、undo段的名字都是以下划线开头的,我们也不去指定使用undo段
事务
一个完整的事务:begin...然后做inster、update、delete...最后commit提交;提交以后事务就完成了
事务的特点:
1、事务的开始
事务开始的方式:
1、begin transaction
2、用户连接数据库以后,发起的第一个DML
3、上一个事务结束之后的第一个DML语句
4、oracle在执行DDL语句之前,会做一个commit,然后执行完DDL之后又再执行一个commit,DDL执行完之后的第一个DDL是一个事物的开始
oracle在执行DDL语句之前,会做一个commit,然后执行完DDL之后又再执行一个commit;在执行DDL语句的时候,前面执行的DML语句被强行提交了
2、事务的结束
事务结束的方式: 1、commit(正常的提交或者正常的退出)
2、rollback(还有非正常的结束;非正常关闭数据库:比如突然停电了)
3、事务的原子性(当一到N个DML属于一个事务时,执行这些DML,要么都成功,要么都失败)
比如现在有这么一个需求:账户A给账户B转账,然后就得更新数据库,对A:update -50,对B:update +50,对于我们来说,这个转账就是一个事务;只要这两个DML属于一个事务,oracle可以保证这两个DML都执行成功,或许都执行失败,不会出现A减去了50而B没有加上50;
所以数据库开发者要清楚地知道和去确认,一笔完整的业务,哪些DML可以分割开来执行,哪些DML不能分割开来执行,也可以将属于两个事务里面的DML在一个事务里面执行,但是还是建议分开执行两个事务
4、事务的隔离性(一个用户更改了一个数据,另外一个用户想去读这个更改的数据,但是另外一个用户是读不到的)
sp1登录数据库以后,将数据库里面的某个1改为了2,但是还没有提交;这时候sp2登进来,要读数据2,因为sp1没有提交,sp2是读不到数据的,sp2是看不到的
一个事务开始以后,oracle数据库要做哪些事情?
图解:
1、在undo表空间里面找到一个相对空闲的undo段;
undo段的段头块里面有事务表(oracle11g里,undo段的段头块里面的事务表可以放34个事务),事务表里面有多行数据,每一行可以放一个事务
2、在一个相对空闲的undo段的段头块的事务表里面找一个空闲的、可用的槽位;
undo段的段头块里面的事务表,事务表里面的34个槽位,找34个槽位里面的空的、可用的空槽;假设1号undo段有30个槽位,2号10个,3号6个,4号5个,依次递减,这时候一个事务开始以后就会用1号段的空槽位;找到槽位之后,写上自己相关的事务信息;对于事务来讲,oracle会给每一个事务分配一个事务xid(相当于事务的身份号)
槽位里面的信息:
1、槽位的编号(比如:1)
2、段的编号(这个槽位属于哪个undo段,比如:5号undo段)
3、段里面的槽位号(在undo段里面的第几个槽位,比如:2号槽位)
4、槽位的使用次数(第几次被覆盖使用了,比如:100次)
5、事务提交之后的SCN号(commit SCN号,不提交时为:null)
6、标志(标志着事务已提交)
7、其他信息
xid的组成:
1、undo段的编号(用了几号undo段)
2、undo段里面事务表的槽位号(用了undo段里面的事务表的哪个槽位)
3、槽位被使用的次数(这个槽位第几次被覆盖):保证了每一个事务的编号是不同的(保证了事务的唯一性,就不会出现两个事务的xid相同的情况)
3、将事务的信息写到空槽位里面去;
记录事务的信息:
图示:
4、做DML操作,修改数据块,修改之前把修改之前的值写到undo里面去;
图解:
oracle在undo段里面找到可用的槽位之后,将事务的信息写进去:xid、SCN号(空的,因为未提交)、事务提交标志(未提交);这里还有一个信息是:dba(data block address:数据块地址),这个地址在一个事务一开始的时候是空的,然后要修改t表,把1改为2,oracle就把1写到undo段里面去,再把数据1所在的数据块的地址记录到槽位的dba位置,dba地址指向1
然后commit提交事务,把提交事务的SCN号和事务提交标志写到槽位里去,这时候,undo里面的数据1还在;下次这个事务槽就可以被其他事务使用了,事务槽能够被覆盖使用的一个前提是:这个事务必须是已经commit提交了的
5、commit提交或者rollback
图解:
然后commit提交事务,把提交事务的SCN号和事务提交标志写到槽位里去,这时候,undo里面的数据1还在;下次这个事务槽就可以被其他事务使用了,事务槽能够被覆盖使用的一个前提是:这个事务必须是已经commit提交了的;
rollback的时候,找到对应的事务编号,事务槽里面的dba在undo里面找到原来的数据,然后取出数据,覆盖表里面已经修改的数据,改回原来的值,最后再commit提交,这时候又是另外的事务提交的SCN号和事务提交标志写到槽位里,事务结束
一个事务里面修改多个块的情况
图解:
修改了多个块,在undo里面,使用了undo的第3个块、第5个块和第6个块,那么dba数据块地址会指向最后一个块地址(第6个块),然后第6个块指向第5个块,第5个块指向第3个块;
回滚的时候,先修改回3,然后修改回2,再修改回1;
有多个事务时候的情况
图解:
一个undo段,段头块里面有三个事务:事务1使用了undo段的3个块,然后事务的dba指向最后一个块;事务2也使用了undo段的3个块,事务的dba指向最后一个块;事务3使用了undo段的2个块,事务的dba指向最后一个块;
然后将来回滚的时候:事务1找到最后的块,然后往前回滚,事务2、3也是如此
所以一个undo段里面:
1、会有多个事务;
2、每一个事务有自己的undo数据链,回滚时候,使用自己的数据块回滚
对于一个事务来讲,它有一个xid,只有事务被提交了,事务表里面的段头块里面的槽位才能被覆盖使用,事务对应的undo段也可以被覆盖使用
事务里面,区的状态
图解:
在事务表的undo段里面,有一个一个的区extent,在区里面的block:
1、只要在block里面有未提交事务,这个区就显示为active(活跃的),这里面的区是不能被重新分配的;
2、如果区已经显示提交了,显示为inactive(不活跃的)
3、如果一个区里面的block,还没有被使用,就显示为free;
oracle默认有一个参数:undo retention,默认为:900秒(15分钟);oracle希望在900秒的时间内尽量不要覆盖事务表里面已经提交的事务所在的槽位,如果提交之后,并且超过900s,则状态为:expired
如果一个事务需要extent的时候,就在事务表空间里找,它首先就找显示为free的undo段来使用,如果没有就找expired(过期),如果expired也没有就找inactive,如果inactive也没有的话,它就会报错,因为显示为active(活跃的),里面的区是不能被重新分配的;
将表空间改为:gurantee属性的话,就是在15分钟之内,保证事务的undo信息一直被保存着
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版