【原创】ORA-04068: 已丢弃程序包 的当前状态研究

不久前在市检的生产环境上有个存储过程执行报错,错误信息如下:

ORA-04068: 已丢弃程序包  的当前状态
ORA-04061: package "ZHANGXSH.PR_TEST" 的当前状态失效
ORA-04065: 未执行, 已更改或删除 package "ZHANGXSH.PR_TEST"
ORA-06508: PL/SQL: 无法找到正在调用 : "ZHANGXSH.PR_TEST" 的程序单元
ORA-06512: 在 line 2

当然这个错误信息是我在我本机试验复现的,不是真实的报错信息,不过都是一样的

开始怀疑是存储过程编译失败造成,但是经过仔细排查,发现没有编译失败,该包所依赖的其他过程、函数、视图等都没有问题。仔细分析了下,发现该包里面有多个全局变量,怀疑是全局变量的问题,于是我在本机做了个测试,将该问题复现了下:
首先在会话1中创建以下包:

CREATE OR REPLACE PACKAGE PKG_TEST AS
  LDLX NUMBER := 1000;
END PKG_TEST;
/

CREATE OR REPLACE PACKAGE BODY PKG_TEST AS
END PKG_TEST;
/

然后创建测试的存储过程:

create or replace procedure pr_test2 as
begin
  PKG_TEST.LDLX := PKG_TEST.LDLX+110;
  dbms_output.put_line(PKG_TEST.LDLX);
end;
/
然后在会话2中执行pr_test2;
SQL> set serveroutput on
SQL> exec pr_test2;

1110

PL/SQL procedure successfully completed

可以成功执行。
然后回到会话1中重新编译PKG_TEST 包。再回到会话2执行存储过程:

SQL> /

begin pr_test2; end;

ORA-04068: 已丢弃程序包  的当前状态
ORA-04061: package "ZHANGXSH.PKG_TEST" 的当前状态失效
ORA-04065: 未执行, 已更改或删除 package "ZHANGXSH.PKG_TEST"
ORA-06508: PL/SQL: 无法找到正在调用 : "ZHANGXSH.PKG_TEST" 的程序单元
ORA-06512: 在 "ZHANGXSH.PR_TEST2", line 3
ORA-06512: 在 line 2

SQL> 

此时,该错误立刻被抛出,原因就是全局变量在会话2中存在一个拷贝,当会话不关闭时,该拷贝会一直存在于pga中,如果该包在此时被重新编译会导致该拷贝失效而报错。在实际测试中发现,该错误出现的概率约为60%左右,也就是说重新编译100次,约会出现60次,而且诡异的是在rh5+10G下面居然不出现该错误,只有当全局变量的值改变时才报该错。原因有待进一步研究。
因此,很多人包括我自己都偏爱存储过程,原因之一就是修改后无需重启中间件立刻生效,这个案例说明,存储过程也是可能发生问题的,因此提供以下避免的方法:

1.全局变量不要和相关的函数、存储过程定义在一个包里面,而是单独定义,单独定义的目的是减少被重新编译的概率。
2.不要使用全局变量,如果要使用,则参考1.

如果已经发生了该错误,解决办法如下:

1.将运行报错的会话kill掉。
2.刷新共享区:alter system flush shared_pool;

 

posted on 2013-12-27 15:49  迷途@书童  阅读(7879)  评论(0编辑  收藏  举报

导航