ORA-04061:包体“PACKAGE.NAME”的现有状态已经失效

时间:2018-03-20 14:53:27

标签: oracle plsql oracle11g oracle12c

在我正在处理的一个Oracle数据库实例上,我在重新编译包时观察到的不同于正常行为。

通常,(在问题Frequent error in Oracle ORA-04068: existing state of packages has been discarded中)在PL / SQL包重新编译之后,第一次调用时会出现以下错误:

ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "PACKAGE.NAME" has been
invalidated
ORA-06508: PL/SQL: could not find program unit being called:
"PACKAGE.NAME"
ORA-06512: at line 1

但是第二次调用应该可以正常工作,假设包当然没有错误。此行为先前存在于该环境中。与此同时,我们从11g R2升级到12c R1,并启用了基于版本的重新定义。

现在我遇到的问题是我一直只是:

ORA-04061: existing state of package body "PACKAGE.NAME" has been
invalidated
ORA-06508: PL/SQL: could not find program unit being called:
"PACKAGE.NAME"
ORA-06512: at line 1

所以没有ORA-04068了,只有修复它的方法是重新连接会话或手动调用DBMS_SESSION.RESET_PACKAGE()(但我不控制所有可能受影响的代码),否则问题仍然存在每次通话。

是否有任何可以调整的数据库参数可以调整?这个问题并不是特定于任何特定的PL / SQL包,并且当它引用的内容发生变化时,似乎可以通过正常的包失效来触发它。

提前谢谢。

3 个答案:

答案 0 :(得分:3)

Oracle这样做是因为重新编译PL / SQL包会使正在使用的任何会话变量无效。

除了使用良好的部署实践外,我们无法避免这种情况。在数据库正在使用时不要部署更改,确保所有连接都已正确断开连接等。在这个CI / CD时代说起来容易做起来难,没有停机时间和其他激动人心的创新。

所以在储物柜后面有一件事:pragma serially_reusable;。此指令表示在单个服务器调用期间维护包的状态。例如,如果我们有一个PL / SQL块,它调用SR过程三次,那么由该过程改变的任何变量将主导三次调用的值。但是下次我们运行块时 - 在同一个会话中 - 变量将被重置为它们的起始值。

串行可重用PL / SQL有一些限制 - 例如,它不能用于SQL查询。但是从您的角度来看,最大的吸引力在于ORA-04068或ORA-04061错误。没有会话状态,无效无效。

必须在包级别,正文和规范中声明

pragma serially_reusable。因此,您必须确保所有打包的过程都不需要跨服务器调用维护状态。

答案 1 :(得分:0)

在将某些DDL指令放入某些程序时,我得到了此错误:

execute immediate ('drop sequence seq_table_1');
execute immediate ('create sequence seq_table_1 increment by 1 start with 1');

即使我没有在程序包中的任何地方调用此(私有)过程,我也通过调用任何其他程序(在程序包主体中将此程序在after(!)之后实现)而收到此错误。 放入pragma serially_reusable;也无济于事。 但是,当我将上述过程的实现移到程序包主体的末尾时,该错误消失了。

答案 2 :(得分:0)

问题出在时间戳上。 如果您有一个脚本,在该脚本中首先创建该程序包然后尝试调用它,则时间戳可能是相同的(尤其是在服务器较强的情况下)。 创建软件包后,我遇到了同样的错误,并通过输入dbms_lock.sleep(2)解决了该问题。