[ORACLE] ORA-01555的异常分析 ,都是大事务惹的祸

ORA-01555 是一个很常见的异常,尤其是对于数据量比较大的系统而言,从字面的意思来看,是快照过旧错误,所谓的快照是什么意思呢?

 

我们知道oracle实现事务是通过一个特殊的区域名字叫“回滚段”来完成,当一个事务开始处理数据的时候,其中的修改过的旧数据会被放入回滚段的随机位置中,并且置位标记为不可覆盖,即表示这个事务还在处理中,当A事务正确提交,则回滚段的数据不会被清空,而是将标记置为可覆盖,意思是这段数据的事务已经提交了,这个存储片可以重新使用了。

那么ORA-01555所谓的快照过旧是什么意思呢?意思就是说回滚段中的数据已经有所更新,旧数据已经不可使用。可能这个概念有点抽象,我们慢慢讲解。

 

举个例子说明一下,假设一个事务A获取处理的数据尚未做分页控制,一次从数据库中获取需要处理的数据有40万条,这时候程序是一条一条的执行下来的。

 

当事务A执行到第10万条的时候,一个新的事务B,对A所需要处理的数据中的第39万条数据进行了修改,这个B事务正确处理了逻辑并成功提交。

 

想想事务B做了什么? 当它开启事务修改数据的时候,某个旧数据被放入了回滚段(假设名称叫 F 位置),并且置其状态为不可覆盖,然后B事务继续执行,或许会操作其他数据表的数据,然后成功提交,然后将回滚段的F位置置位为可覆盖了。

 

好了,其实B事务在这个例子中不需要关注太多,只要知道它修改了我们事务A的一条待处理数据即可,并且这个时候回滚段中的数据还存在着。

 

试想,如果事务A这个时候执行到第39万条数据,它发现数据已经被修改了,它会怎么做?它会从回滚段中把旧数据读出来(假设事务的隔离级别为read-commited),然后进行处理。这个过程是不会有问题的。

 

但是很悲剧的是,这时候,一个新的事务C,在A尚未来得及处理第39万条数据的时候,做了一些事情,具体做了什么事情不需要管,其中关注的一点是,它做的事情的后果是,它也使用了回滚段,并且使用到了回滚段的F位置!想想我们刚才讲的,F位置放着A需要的数据呢,但是很悲哀的由于F位置的标志是可覆盖,所以C事务很坦然的覆盖掉了,放上了自己的数据。然后提交,然后结束。

 

这个时候,A事务执行到了第39万条数据,我们上面讲了,他会发现这条数据被修改了,会去回滚段中获取旧数据,但是,刚才的数据已经被C事务给覆盖掉了!它找不到了,所以,它会抛出ORA-01555快照过旧的异常。

 

通过上面的描述,你体会下这个名称:快照过旧。是不是有那么点意思?

 

好了,现在我们知道了为什么会有这个异常,那么问题出在哪里?为什么我们的代码会抛出这样异常呢?

很明显,事务过大导致,获取数据尚未进行控制,导致一个大事务的运行难免会遇到这样的问题。别忘了现在我们处于的是多核集群部署的环境下,这样的问题很容易爆发。

 

所以,简化你的事务,别让他显得太过于臃肿,高效简洁才是追求。

 

上面提到的知识如果你不太了解,这里我简单补充几点:

 

1、事务的传播级别,隔离级别。这个我重新开贴再讲。

2、oracle回滚段。这个是dba需要了解的概念,回滚段的使用是循环的,类似于一个循环列表的遍历过程,相当的低碳,呵呵,有一个标记,用于标示当前的位置,是否可以被使用,也是底层实现事务回滚数据恢复的一种重要机制。

 

上述的问题我在支付宝遇到过一次,支付宝的高并发的系统如果逻辑处理不当,很容易出现上述问题。如果你还有什么不明白,可以动手做做实验,调试下看看结果。

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值