欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Oracle数据库对象失效问题

程序员文章站 2022-06-02 15:39:35
...

在日常运维过程中,我们会发现Oracle数据库的一些对象(view、package、type、procedure等)会变成失效状态(invalid)。造成失效的原因有很多,大体可以分成两大类:

 

1.对象本身编译报错。

这种情况很可能发生在新建过程或者程序包上,或者对已有的程序包或过程进行修改时。

对于这种编译错误只需要找到编译报错位置,根据错误提示进行修改并重新编译即可。

检查/编译失效数据库对象可以通过以下SQL来实现。

--检查失效对象 
SELECT * FROM dba_objects WHERE status = 'INVALID'; 
SELECT * FROM dba_invalid_objects; 
--编译失效对象 
BEGIN 
    dbms_utility.compile_schema('schema_name', false); 
END; 
--查询编译报错信息 
SELECT * FROM dba_errors WHERE owner = 'schema_name';

 

2.被引用对象结构发生改变

当某些对象(通常为table、view、type等)的结构发生改变时,依赖这个对象的其他对象也可能变为失效状态(invalid)。

查看对象依赖关系可以通过以下SQL来实现。

SELECT * FROM dba_dependencies WHERE name = 'object_name' AND owner = 'schema_name'; 
SELECT * FROM all_dependencies WHERE name = 'object_name' AND owner = 'schema_name'; 
SELECT * FROM user_dependencies WHERE name = 'object_name' AND owner = 'schema_name';

对于这类失效对象,对象本身是不存在任何错误的,只需要使用上述的失效包编译方法重新编译一下即可。

此外,对象结构的改变也可能造成某些对象的状态虽然非失效状态,但是某些应用在调用该对象时(外部应该调用存储过程)会提示对象失效。提示信息如下:

ORA-04068: 已丢弃程序包 的当前状态 
ORA-04061: package body "ENSEMBLE.XUTEST" 的当前状态失效 
ORA-04065: 未执行, 已变更或删除 package body "ENSEMBLE.XUTEST"

 

这种状态的出现可能(我是通过试验得出的结论)与数据库的会话缓存有关。当一个会话连接数据库并执行某个存储过程(以调用存储过程为例,也可能发送在执行SQL语句中)时,数据库会在该会话中创建该过程的版本信息,当该过程发生DDL时(该对象本身或者依赖对象发生改变时,该对象的 last_ddl_time 会随之改变),该会话中的对象版本即变成旧的版本。此时仍然使用该会话去调用该对象就会出现上面的报错信息。

 

以下为我的试验过程:

会话A中存在程序包 xutest

包头如下:(包头中包含全局变量)

create or replace package xutest is
 -- Author : XU
 -- Created : 2019/12/12 11:32:07
 -- Purpose : invalid test
 -- Public function and procedure declarations
 v_aaa aaaaaa%rowtype;
 function testinvalid return varchar2;
end xutest;

 

包体如下:

create or replace package body xutest is
 -- Function and procedure implementations
 function testinvalid RETURN VARCHAR2 is
     begin
         select * into v_aaa from aaaaaa where rownum = 1;
         dbms_output.put_line(v_aaa.bb);
         return v_aaa.cc;
     end testinvalid;
 end xutest;

 

在会话B中调用该包中的 testinvalid 方法

select XUTEST.testinvalid from dual;

第一次调用时,执行正常,并返回对应结果。

此时在A会话中对 xutest 包的包体进行任意修改,并重新编译(或者修改过程中依赖的表 aaaaaa 的表结构)。

这时使用失效对象查询语句查询当前处于失效状态的对象,发现查询结果中并没有 xutest 包。

在B会话中再次调用 testinvalid 方法,此时会报错如下:

ORA-04068: 已丢弃程序包 的当前状态
ORA-04061: package body "ENSEMBLE.XUTEST" 的当前状态失效 
ORA-04065: 未执行, 已变更或删除 package body "ENSEMBLE.XUTEST"

这时在B会话中再次调用 testinvalid 方法,执行正常,并返回对应结果。(对象版本已经刷新为最新版本)

 

我在试验中发现,只有包头中存在全部变量的过程才可能会存在这种现象。

其实在外部应用调用存储过程时,如果出现这种情况只需要应用与数据库重新建立会话连接(或者重启应用)即可,在新的会话中是不存在旧的对象版本信息的。