【问题标题】:ORA-04061: existing state of package body "PACKAGE.NAME" has been invalidated persistsORA-04061: 包主体 "PACKAGE.NAME" 的现有状态已失效持续存在
【发布时间】:2018-08-29 11:00:59
【问题描述】:

在我正在处理的一个 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 包,它似乎可以在其引用的内容发生更改时由正常的包失效触发。

提前谢谢你。

【问题讨论】:

    标签: oracle plsql oracle11g oracle12c


    【解决方案1】:

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

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

    所以储物柜后面有一个东西:pragma serially_reusable;。该指令意味着包的状态在单个服务器调用期间保持。例如,如果我们有一个 PL/SQL 块,它调用一个 SR 过程三次,由该过程更改的任何变量都将在这三个调用中保持值。但是下次我们运行该块时 - 在同一个会话中 - 变量将被重置为它们的起始值。

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

    pragma serially_reusable 必须在包级别、正文和规范中声明。因此,您必须确保没有一个打包过程需要跨服务器调用维护状态。

    【讨论】:

    • 感谢您的回复,但我的问题是不再有 ORA-04068 错误,我一直只收到 ORA-04061。这不是我在asktom.oracle.com 和其他论坛上收集到的典型行为。
    • 串行可重用修复 ORA-04061。
    【解决方案2】:

    当我将 DDL 指令放入某些程序时出现此错误,例如:

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

    即使我没有在包中的任何地方调用此(私有)过程,但通过调用任何其他过程(在包主体中的此过程之后(!)实现)得到了此错误。 放置pragma serially_reusable; 也无济于事。 但是当我把这个提到的过程的实现移到包体的末尾时,错误就消失了。

    【讨论】:

      【解决方案3】:

      问题在于时间戳。 如果您有一个脚本,您首先创建包然后尝试调用它,则时间戳可能是相同的(特别是如果服务器很强大)。 我有同样的错误,创建包后输入dbms_lock.sleep(2)解决了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-26
        • 1970-01-01
        • 2019-09-23
        • 2014-11-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多