ACCESSIBLE BY 是 Oracle 12c 引入的编译期可见性约束机制,仅用于包规范中私有成员声明,限定可调用该成员的程序单元,不提供运行时权限校验,本质是封装强化工具而非访问控制。

ACCESSIBLE BY 是 Oracle 12c 引入的访问控制机制,用于显式声明哪些程序单元(如包、过程、函数、类型)可以调用当前 PL/SQL 单元中的私有对象。它不提供运行时权限校验,而是在编译期强制执行可见性约束——不是权限控制,而是封装强化工具。
ACCESSIBLE BY 的作用范围与语法限制
- 只能用于 包规范(package specification) 中的子程序、变量、常量、游标等私有成员的声明处,不能用于包体(package body)内部定义。
- 不支持在匿名块、触发器、函数、过程或类型体中直接使用该子句。
- 必须配合
PRAGMA RESTRICT_REFERENCES或DETERMINISTIC等旧机制使用,但两者目的不同:ACCESSIBLE BY管“谁可以调”,而PRAGMA管“能做什么”。
示例:
将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。
CREATE OR REPLACE PACKAGE pkg_utils AS
-- 允许仅 pkg_api 和 proc_maint 调用此函数
FUNCTION get_config_value(p_key VARCHAR2)
RETURN VARCHAR2
ACCESSIBLE BY (PACKAGE pkg_api, PROCEDURE proc_maint);
END;
/
常见错误:误以为它能控制运行时调用或跨 schema 访问
-
ACCESSIBLE BY不检查调用者是否拥有 EXECUTE 权限,也不验证 schema。如果pkg_api在另一个 schema(如app_user),而当前用户没有EXECUTE ON app_user.pkg_api,编译会失败,但失败原因是权限缺失,不是ACCESSIBLE BY拦截。 - 若声明为
ACCESSIBLE BY (PROCEDURE my_proc),但my_proc尚未创建或不在同一 schema,编译报错:PLS-00904: insufficient privilege to access object或PLS-00201: identifier must be declared。 - 它对动态 SQL(
EXECUTE IMMEDIATE)完全无效——任何能拼出合法调用语句的地方都能绕过。
实际部署时必须注意的三点
- 使用前确认 Oracle 版本 ≥ 12.1.0.1;11g 及更早版本不识别该语法,直接报错
PLS-00103: Encountered the symbol "ACCESSIBLE"。 - 如果包已存在,修改时需重建整个包规范(
DROP+CREATE),仅CREATE OR REPLACE无法更新ACCESSIBLE BY列表。 - 无法通过
DBA_SOURCE或ALL_SOURCE直接查出该子句内容——它被编译进数据字典的依赖关系中,只能通过ALL_PROCEDURES.ACCESSIBLE_BY视图(Oracle 12.2+)或解析DBA_SOURCE文本间接确认。
真正起作用的点在于:它让“封装意图”变成可审计、可版本控制的代码契约。一旦团队约定某函数仅供特定入口调用,这个子句就能在开发阶段就挡住随意引用,而不是等上线后靠 Code Review 或文档去提醒。但别指望它替代权限模型或防止 SQL 注入。

















