重编译包体(alter package ... compile body)会强制丢弃所有会话中该包的运行时状态,导致后续调用触发ora-04068错误;只有完整重编译包头(alter package ... compile)、新建会话或应用层捕获后重试才能重建状态。

重编译包体时会清空包状态,导致调用者报 ORA-04068
Oracle 的 PACKAGE 不只是代码容器,它还维护运行时状态(比如全局变量、初始化块执行结果)。当你执行 ALTER PACKAGE xxx COMPILE BODY 时,Oracle 会丢弃当前所有会话中该包的缓存状态——这不是 bug,而是设计行为。此时若某个 JDBC 连接正持有一个旧状态副本,下一次调用该包内任意过程,就会立刻触发 ORA-04068: existing state of packages has been discarded,并伴随 ORA-04061 和 ORA-06508。
为什么单纯重编译调用者过程无法解决 ORA-04068
假设过程 P_MAIN 调用了包 PKG_UTILS 中的函数,你只对 P_MAIN 执行 ALTER PROCEDURE P_MAIN COMPILE:
- 这只能修复
P_MAIN自身的语法或依赖引用问题,不触碰PKG_UTILS的状态 -
PKG_UTILS的包状态仍被标记为“已丢弃”,下次调用仍会报ORA-04068 - 即使
P_MAIN编译成功,只要它内部访问了PKG_UTILS的变量或常量,就必然失败
哪些操作会真正重置包状态
只有以下两类操作能强制重建包状态(即让后续调用不再报 ORA-04068):
-
ALTER PACKAGE pkg_name COMPILE(注意:不是COMPILE BODY,这是完整重编译,会重跑初始化块) - 客户端主动断开并新建数据库连接(会话级状态彻底刷新)
- 在应用层捕获
ORA-04068后重试一次(第二次调用时 Oracle 已自动重建状态,必成功)
而 ALTER PACKAGE pkg_name COMPILE BODY 或 CREATE OR REPLACE PACKAGE BODY 都不会重跑包初始化逻辑,只会保留“状态已失效”的标记。
依赖链越深,失效传播越隐蔽
一个包 A 引用包 B,B 又引用包 C,C 里有全局变量。这时只要有人对 C 执行了 COMPILE BODY,A 和 B 的调用者全都会在首次调用时收到 ORA-04068 —— 即使 A、B 自身没动过。这种跨包状态传染很难靠查 ALL_OBJECTS.STATUS 发现,因为 A 和 B 的 STATUS 仍是 VALID。真正该查的是 ALL_DEPENDENCIES 递归链上所有被引用包的最后编译时间与当前会话状态是否同步。











