Oracle数据库对象失效问题
在日常运维过程中,我们会发现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 方法,执行正常,并返回对应结果。(对象版本已经刷新为最新版本)
我在试验中发现,只有包头中存在全部变量的过程才可能会存在这种现象。
其实在外部应用调用存储过程时,如果出现这种情况只需要应用与数据库重新建立会话连接(或者重启应用)即可,在新的会话中是不存在旧的对象版本信息的。
上一篇: [数据库]联合主键(复合主键)
下一篇: 数据库插入数据返回主键