【发布时间】:2014-05-12 16:37:30
【问题描述】:
我有一个 JDBC 会话引用 PL/SQL 包的场景。当我更改包主体并重新编译它时,会话不会引发任何异常,但是当我重新编译包规范时,它会引发以下异常。我的问题是为什么当包体更改时会话不会抛出任何异常,如果我在包体中进行更改,现有会话会看到更改吗?
ORA-04068: existing state of packages has been discarded
【问题讨论】:
我有一个 JDBC 会话引用 PL/SQL 包的场景。当我更改包主体并重新编译它时,会话不会引发任何异常,但是当我重新编译包规范时,它会引发以下异常。我的问题是为什么当包体更改时会话不会抛出任何异常,如果我在包体中进行更改,现有会话会看到更改吗?
ORA-04068: existing state of packages has been discarded
【问题讨论】:
如果 PL/SQL 包具有全局变量(常量或可修改),则认为该包具有状态。如果更改包,变量会重新初始化并且状态会丢失。
如果一个数据库会话已经使用了这个包,它在下次访问这个包时会得到一个 ORA-04068 异常。如果它处理了异常,则它可以继续使用该包而不会再次收到异常。当然,状态丢失,应用新版本的包。
对于没有全局变量的 PL/SQL 包,不会引发错误。新版本的软件包立即适用于所有会话。
那么,如果更改后的包不再在该会话中使用,您为什么希望该会话抛出异常?这会导致比增加价值更多的问题。
【讨论】:
阅读Reasons to use Packages中的“更简单的应用程序设计”和“隐藏的实现细节”部分
“包编写指南”部分(同一页)中的所有文档都明确指出:
在包装规范中,仅声明必须对 调用程序。
这种做法可以防止其他开发人员构建不安全的 依赖于您的实现细节并减少对 重新编译。
如果你改变包规范,你必须重新编译任何 调用包的公共子程序的子程序。如果你 只改变包体,你不需要重新编译那些 子程序。
【讨论】:
这是一个众所周知的问题。 在这里你可以找到如何解决它的任何细节。 http://laurentschneider.com/wordpress/2010/12/how-to-solve-ora-4068.html.
但是如果你对全局变量要非常小心!如果它们在你的包中使用,那么当其他程序正在使用它时不要编译你的包。
从 dba 的角度来看,通过 v$access 视图可以知道谁拥有这个包的“锁”。因此,您可以通过 ddl 上的触发器引发编译。
【讨论】: