相信很多人都见过这样的错误,通常是一个程序运行了很久很久,突然报一个快照过旧的红色错误。
那么什么叫作快照过旧呢?它是如何产生的呢?我们应当如何避免呢?
快照过旧是指Oracle尝试读取一个过去时间点的表的数据,然而这些数据已经不在回滚段中存在了。
为什么会有这种情况呢?
这要牵涉到Oracle独特的多版本特性,它会通过回滚段来保证读数据的一致性:Oracle读取的数据,总是某一个时间点的表数据,无论后面表有多大改变,Oracle总尝试读到最开始时间点的所有数据。
举例来说:
1. 进程1在A时刻读取T表所有数据 select * from T;
2.
进程1读到T表的一半,此刻为进程2删除了T表的所有数据,并且提交了。
delete
from T;
commit;
3. 此刻,进程1会继续尝试读取A时刻,T表中的所有数据。
以上便是Oracle引以为豪的多版本特性,这一特性带来了诸多好处,比如这样做既使得读数据不会阻塞任何写动作,也不会被任何写动作阻塞,同时保证了读数据的一致性。
那么Oracle如何做到这一点呢?为什么在T表数据已经被删掉且已经commit的时候,还可以读到其被删除前的数据呢?
简单的说,就是因为在执行delete from
T语句时,Oracle生成了回滚信息在回滚段,倘若这时用户执行Rollback,Oracle可以通过这些回滚信息将删除动作回滚掉。
但是,当用户commit了之后