我得到了以下例外:
Caused by: java.sql.SQLException: ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "PACKAGE_A" has been invalidated
ORA-04065: not executed, altered or dropped package body "PACKAGE_A"
ORA-06508: PL/SQL: could not find program unit being called: "PACKAGE_A"
版本:
Java 1.7.x and oracle 11.4.x
根本原因: PACKAGE_A
具有全局变量声明的状态。包装规格(不是主体)已经重新编译并且已经重新编译。内部调用PACKAGE_B
的java服务调用PACKAGE_A
抛出此异常,直到我们重新启动这些服务。
我知道状态不应该出现包规范。但我正在寻找可行的解决方案 ,而无需在JAVA中进行代码更改
我找到了关于这个主题的其他SE问题的两个解决方案。
选项1:
Defining packages with `PRAGMA SERIALLY_REUSABLE`
选项2:
exec DBMS_SESSION.RESET_PACKAGE
exec DBMS_SESSION.MODIFY_PACKAGE_STATE( DBMS_SESSION.REINITIALIZE)
选项3:
从包中删除全局变量。
如果我没有永远使用选项3,那么使用选项1&的缺点是什么?选项2?
这些选项会导致数据库的性能开销吗? 选项3是否提供了最佳解决方案?
答案 0 :(得分:1)
这是Oracle的标准行为,因为它将包的编译实例保存在每个会话的会话内存中。由于所有包状态在会话中都是有效的(即包变量在两个数据库会话中可以具有不同的值),因此包变量值也会绑定到会话。
现在,如果您更改了包,Oracle必须为所有会话重新加载包。到现在为止还挺好。但是,当您更改代码时,包变量会丢失。这就像在代码更改后停止并重新启动应用程序 - 变量会丢失。
这个优雅的例外表明现在包变量正在丢失。
根据您使用包变量的方式,这可能会导致您的应用程序出现问题 - 因此例外。
但在现实生活中,使用所有包变量以便按需初始化(例如使用plsql表进行oldschool缓存),并且没有人应该保留持久数据(例如,购物车的内容)包变量中的网店应用程序。实际上,包变量 - 虽然看起来是持久的 - 应被视为瞬态,并且在调用之间具有乐观的持久性。
如果您可以遵守此规则,那么您可以非常轻松地处理此异常:
即: