包规范是接口,包体是实现;包规范只声明公有元素(类型、变量、游标、过程/函数签名等),不包含逻辑;包体实现这些声明,并可定义私有元素,二者必须同名且须先建规范再建包体。

包规范是接口,包体是实现
包规范(PACKAGE)只声明能被外部调用的元素,不包含任何可执行逻辑;包体(PACKAGE BODY)则负责实现这些声明,且可额外定义仅在包内可见的私有内容。两者必须同名,但可以分开创建、编译和修改。
包规范里能写什么,包体里不能写什么
包规范中允许声明:TYPE、CONSTANT、variable、cursor、PROCEDURE、FUNCTION、EXCEPTION —— 但所有子程序都只能写签名,不能带 BEGIN / END 块或具体逻辑。
包体中必须实现规范中声明的所有子程序,且签名(参数名、类型、顺序、返回值)必须完全一致;包体中还能定义规范里没提的私有项,比如:
-
v_temp_counter NUMBER := 0;(私有变量,外部不可见) -
FUNCTION validate_input(...) RETURN BOOLEAN IS ...(私有函数,仅供包内其他过程调用)
为什么先建规范再建包体,而不是反过来
因为 Oracle 要求包体依赖已存在的规范。如果先尝试创建 PACKAGE BODY my_pkg,而 my_pkg 规范尚未存在,会报错:PLS-00304: cannot compile body of 'MY_PKG' without its specification。
常见误操作包括:
- 拼错包名(大小写敏感,除非加双引号)
- 在规范中声明了
PROCEDURE p1(p_id IN NUMBER),但在包体中写成PROCEDURE p1(p_id IN VARCHAR2)→ 报PLS-00323 - 包规范里漏掉某个函数声明,却在包体中实现了它 → 该函数对外不可调用,变成“幽灵私有函数”
包变量生命周期和作用域差异
包规范中声明的变量(如 v_seq NUMBER := 0;)是“会话级全局变量”,只要会话未断开,其值就在整个包内持续存在;而包体中声明的变量(即使在包体顶层)属于私有变量,也享同样生命周期,但外部根本访问不到。
这点容易被忽略:同一个包在多个会话中运行时,每个会话的包变量是隔离的;但若误把状态逻辑全压在包变量上,又没做并发控制,可能在高并发下出现意外交互。


















