跨PDB访问本质是跨容器而非跨数据库,Oracle 19c不支持跨PDB直接授权;合法路径仅有数据库链接(DBLINK)或代理PDB(PROXY PDB),ANY权限也无法穿透PDB边界。

跨PDB访问本质是跨容器,不是跨数据库
Oracle 19c中不存在“跨PDB直接授权”这回事。PDB之间物理隔离、数据字典独立,GRANT SELECT ON schema.table TO user 这类语句在当前PDB内执行,只能授予本PDB内对象的权限;目标PDB里的用户根本看不到源PDB的对象,更谈不上被授予权限。真正能实现跨PDB数据访问的,只有两种合法路径:数据库链接(DBLINK)或代理PDB(PROXY PDB)。任何试图用GRANT ... TO user@pdb2或类似语法的操作都会报错 ORA-00942: table or view does not exist 或 ORA-01917: user or role 'xxx' does not exist。
用DBLINK实现跨PDB对象访问(最常用)
这是生产环境最可控、最主流的方式。关键点在于:DBLINK必须建在**目标PDB**(即需要读取数据的那个PDB)里,指向**源PDB**的某个用户,并且该用户已在源PDB中被明确授予了对应对象权限。
- 先在源PDB(如
PDB_SRC)中创建用户并授权:ALTER SESSION SET CONTAINER = PDB_SRC; CREATE USER src_app IDENTIFIED BY pwd123; GRANT CREATE SESSION TO src_app; GRANT SELECT ON hr.employees TO src_app;
- 再切换到目标PDB(如
PDB_DST),创建指向源PDB服务名的DBLINK:ALTER SESSION SET CONTAINER = PDB_DST; CREATE DATABASE LINK dbl_src CONNECT TO src_app IDENTIFIED BY pwd123 USING 'pdb_src_service'; -- 注意:这是tnsnames.ora中配置的服务名,不是PDB名
- 在
PDB_DST中即可查询:SELECT * FROM hr.employees@dbl_src WHERE rownum < 10;
- 注意:
USING子句必须指向一个可解析的网络服务名(TNS alias),不能写成'localhost:1521/pdb_src'这类直连串——Oracle不支持在DBLINK中使用EZCONNECT语法。
用PROXY PDB实现透明访问(适合统一治理场景)
代理PDB把远端PDB“挂载”为本地的一个逻辑PDB,用户无需显式写@dblink,像访问本地对象一样查询。但它要求源CDB开放CREATE PLUGGABLE DATABASE权限,并且网络、密码文件、SSL配置都需对齐。
- 源CDB(
CDB2)需创建带CONTAINER=ALL的通用用户:CREATE USER c##proxy_admin IDENTIFIED BY pwd456 CONTAINER=ALL; GRANT CREATE SESSION, CREATE PLUGGABLE DATABASE TO c##proxy_admin CONTAINER=ALL;
- 目标CDB(
CDB1)先建DBLINK指向源CDB的管理员:CREATE DATABASE LINK link_cdb2 CONNECT TO c##proxy_admin IDENTIFIED BY pwd456 USING 'cdb2_tns';
- 再执行代理创建:
CREATE PLUGGABLE DATABASE proxy_hr AS PROXY FROM hr_pdb@link_cdb2;
- 打开后,在
CDB1中可直接查:ALTER SESSION SET CONTAINER = proxy_hr; SELECT * FROM hr.employees;
为什么不能用ANY权限绕过?
SELECT ANY TABLE这类ANY权限只在**同一容器内**生效,它不会穿透PDB边界。即使你在CDB$ROOT给某个通用用户授予SELECT ANY TABLE CONTAINER=ALL,该用户登录到PDB_A时,仍无法访问PDB_B中的表——因为PDB_B的数据字典对PDB_A不可见。强行尝试会触发ORA-00942,而不是权限不足错误。这也是最容易被误解的一点:权限作用域由容器决定,不是由用户身份宽泛性决定。


















