包规范必须先创建,声明公共接口且不包含实现;包体后建,实现逻辑并可定义私有元素;AUTHID需显式指定且两者一致,否则调用报错。

直接创建包规范(PACKAGE)和包体(PACKAGE BODY)即可完成初始化,但顺序不能错、权限不能少、AUTHID 选型必须明确 —— 否则调用时会报 PLS-00201: identifier must be declared 或 ORA-00904: invalid identifier。
包规范必须先建,且不能依赖包体里的内容
包规范是接口声明,所有对外暴露的变量、常量、类型、函数、过程都得在这里定义。它不包含实现逻辑,也不允许引用尚未声明的私有元素。
-
CREATE OR REPLACE PACKAGE必须在CREATE OR REPLACE PACKAGE BODY之前执行 - 包规范里声明的游标、函数、过程名,在包体中必须严格一致(大小写不敏感,但建议统一小写)
- 不能在包规范里引用包体中才定义的私有类型或变量;否则编译失败,报
PLS-00201 - 如果用了
TYPE声明嵌套表或关联数组,该类型必须在包规范中完整定义,不能只在包体里写
包体里可以声明私有元素,但不能暴露给外部
包体是实现层,除了实现规范中声明的公共子程序,还能定义仅本包可见的私有变量、常量、类型和子程序。这些不会出现在调用者的命名空间里。
- 私有变量如
g_counter NUMBER := 0;只在包体内生效,外部查不到,也改不了 - 私有过程(如
PROCEDURE validate_input)不能被包外调用,否则报PLS-00221: 'XXX' is not a procedure or is undefined - 包体顶部的声明段(
IS/AS后)可放私有内容;结尾的初始化块(BEGIN ... END;)会在首次调用该包任意元素时执行一次 - 初始化块里不能有 DML 或事务控制语句(如
COMMIT),否则报ORA-04062: timestamp mismatch或运行时报错
AUTHID CURRENT_USER 和 AUTHID DEFINER 决定权限上下文
默认是 AUTHID DEFINER(以包属主身份执行),但多数业务包应显式写成 AUTHID CURRENT_USER,否则调用者可能因无表权限而失败。
- 不写
AUTHID就是DEFINER:SQL 语句按包属主(如SCOTT)权限解析,调用者哪怕有SELECT权限也查不了自己表 -
AUTHID CURRENT_USER:SQL 按调用者权限解析,适合通用工具包(如日志记录、参数校验) - 包规范和包体的
AUTHID必须一致,否则编译报PLS-00957: inconsistent AUTHID declaration - 含动态 SQL(
EXECUTE IMMEDIATE)的包,CURRENT_USER更安全,避免硬编码属主名
常见初始化失败原因与验证方式
建完包规范和包体后,别急着调用。先确认编译状态和依赖是否干净。
- 查编译错误:
SELECT * FROM USER_ERRORS WHERE NAME = 'YOUR_PACKAGE_NAME'; - 检查是否有效:
SELECT STATUS FROM USER_OBJECTS WHERE OBJECT_NAME = 'YOUR_PACKAGE_NAME' AND OBJECT_TYPE = 'PACKAGE';(必须是VALID) - 包体无效时,即使包规范有效,调用也会报
ORA-04068: existing state of packages has been discarded - 若包里用了
DBMS_OUTPUT.PUT_LINE,记得在 SQL*Plus 或 SQL Developer 中先运行SET SERVEROUTPUT ON - 不要在包规范里写
PRAGMA AUTONOMOUS_TRANSACTION—— 它只能出现在子程序内部
最易被忽略的是包级变量的会话级持久性:一旦初始化块执行过,g_call_count 这类变量在整个会话生命周期内都保持值,跨多次存储过程调用不重置。这在连接池场景下极易引发状态污染,务必谨慎设计初始化逻辑。











