必须先确认连接到目标pdb而非cdb$root:执行select sys_context('userenv','con_name') from dual验证,若返回cdb$root则需alter session set container=your_pdb_name或重连指定pdb服务名。
在pdb中写pl/sql和传统oracle没区别,但必须先连对容器——连错地方写的包、过程、函数全在cdb$root里,pdb里根本看不见。
确认当前连接的是目标PDB而不是CDB$ROOT
很多人写完CREATE OR REPLACE PROCEDURE发现PDB里查不到,其实是连在CDB$ROOT里执行的。用这条命令立刻验证:
SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL;
返回值要是CDB$ROOT,说明你正在根容器里操作;必须切换过去:
- 用
ALTER SESSION SET CONTAINER = your_pdb_name;(需有SET CONTAINER权限) - 或者更稳妥:断开重连,显式指定服务名,比如
sqlplus user/pass@host:port/your_pdb_service - 注意:TNSNAMES.ORA里服务名必须指向PDB,不是CDB全局服务名;常见错误是服务名配成
ORCL(CDB名),实际该用ORCLPDB1这类PDB专属服务名
本地用户才能在PDB里创建PL/SQL对象
公用用户(c##xxx)默认能连PDB,但不能直接在PDB里建存储过程——除非你显式用CONTAINER=CURRENT并已授予权限。更简单可靠的做法是用本地用户:
- 必须在目标PDB里创建,例如:
CREATE USER app_user IDENTIFIED BY pwd;(不能在CDB$ROOT里执行) - 本地用户无需
c##前缀,名字可自由定义,且只存在于当前PDB - 授
CREATE PROCEDURE、CREATE PACKAGE等权限时,不用加CONTAINER=子句,它天然只对当前PDB生效 - 如果硬要用公用用户写PL/SQL,得先在CDB$ROOT里执行:
GRANT CREATE PROCEDURE TO c##user CONTAINER=ALL;,否则即使连进PDB也报ORA-01031: insufficient privileges
PL/SQL编译失败时,错误信息可能藏在CDB视图里
在PDB中执行CREATE OR REPLACE FUNCTION报错,但SHOW ERRORS没输出?因为编译错误默认记录在CDB层级的CDB_ERRORS里:
- 查当前PDB里的错误:用
SELECT * FROM ALL_ERRORS WHERE OWNER = 'APP_USER';(ALL_ERRORS自动过滤当前容器) - 别用
USER_ERRORS——它只显示当前会话用户的对象错误,但如果你用公用用户登录,USER_ERRORS可能为空 - 调试时建议加
PRAGMA AUTONOMOUS_TRANSACTION的日志写入语句,日志表也得建在当前PDB的本地用户下,否则事务跨容器会失败
DBMS_OUTPUT.PUT_LINE在PDB里不显示?检查会话级设置
写了DBMS_OUTPUT.PUT_LINE但SQL*Plus或SQL Developer里没输出,大概率是没开启缓冲区或连错了容器:
- 先确认是否在目标PDB会话中执行:
SELECT SYS_CONTEXT('USERENV','CON_NAME') FROM DUAL; - 执行
SET SERVEROUTPUT ON(SQL*Plus)或勾选“启用DBMS输出”(SQL Developer) - 如果用了
DBMS_OUTPUT.ENABLE(1000000)但缓冲区仍满,错误不会报出,只会静默丢弃——这是最容易被忽略的静默失败点 - PDB之间
DBMS_OUTPUT完全隔离,一个PDB里ENABLE不影响另一个
真正麻烦的从来不是语法,而是容器上下文——写PL/SQL前多敲一次SYS_CONTEXT('USERENV','CON_NAME'),能省掉后面半小时翻日志的时间。











