oracle 19c 不支持“grant select any table on schema”语法,该语法首次出现在23c;19c中实现schema级只读需通过角色封装对象级授权,并注意备库限制、create session授权、账号锁定及闪回权限等闭环要求。

Oracle 19c 不支持真正的 Schema 级别只读授权语法,所谓“GRANT SELECT ANY TABLE ON SCHEMA xxx”在 19c 中根本不存在,执行会直接报错 ORA-01931。
为什么SELECT ANY TABLE ON SCHEMA在19c中无效
这是最常被误传的点。Oracle 19c 的权限模型里没有 ON SCHEMA 这种语法修饰符——它首次出现在 23c 才作为正式特性引入。你在 19c 里写 GRANT SELECT ANY TABLE ON SCHEMA HR TO user,Oracle 会立刻拒绝:ORA-01931: cannot grant SELECT ANY TABLE。这不是权限没刷、不是备库限制、也不是大小写问题,是语法层面不识别。
常见错误现象包括:
- 复制了 23c 文档里的命令,在 19c 环境执行失败
- 误以为 ADG 备库上能用这个语法绕过对象级授权
- 脚本自动化时硬编码了该语法,导致批量授权中断
在19c中实现等效Schema级只读的唯一可行路径
必须退回到对象级显式授权,但可通过角色封装模拟 Schema 级控制效果。关键不是“省事”,而是“可控+可审计”。
操作要点:
- 先确认目标 schema 下所有需开放的表/视图:使用
DBA_OBJECTS而非ALL_TABLES(后者可能漏掉视图、物化视图) - 限定类型:
OBJECT_TYPE IN ('TABLE', 'VIEW', 'MATERIALIZED VIEW'),跳过BIN$%(回收站)、AUD$(审计表)、LOGMNR%(日志挖掘表)等敏感对象 - 生成授权语句时,
OWNER和OBJECT_NAME必须全大写(除非建对象时用了双引号) - 授权目标必须是角色,不是用户;再把角色授给用户,避免后续增表时反复改用户权限
示例脚本(在备库或主库上执行,取决于部署场景):
SELECT 'GRANT SELECT ON ' || OWNER || '.' || OBJECT_NAME || ' TO app_readonly;'
FROM DBA_OBJECTS
WHERE OWNER = 'CMSPROD'
AND OBJECT_TYPE IN ('TABLE', 'VIEW', 'MATERIALIZED VIEW')
AND OBJECT_NAME NOT LIKE 'BIN$%'
AND OBJECT_NAME NOT LIKE 'AUD$%';
ADG备库上必须额外注意的三件事
如果目标是物理备库(READ ONLY WITH APPLY),哪怕上面跑的是 19c,也必须遵守备库硬限制:
-
SELECT ANY TABLE在备库上一定失败,不是权限没生效,是内核禁止其校验过程访问字典表(如obj$),会抛 ORA-01031 - 所有
GRANT SELECT ON schema.table TO role语句,必须在备库实例上执行(不能只在主库授,指望同步) - 同义词(SYNONYM)和视图(VIEW)若被应用直接引用,其底层依赖的对象也必须已授权——视图本身不继承权限,查视图失败往往是因为某张基表没授 SELECT
容易被忽略的权限闭环动作
授权完成 ≠ 可用。漏掉以下任意一项,用户登录后仍会报 ORA-01031 或 ORA-00942:
-
CREATE SESSION必须显式授予用户(角色不带连接能力) - 用户账号建议锁定:
ALTER USER cmsreadonly ACCOUNT LOCK,防止交互式滥用 - 若应用通过 JDBC 使用
currentSchema参数,Oracle 19c 不支持该参数,SQL 中必须显式写CMSPROD.TABLE_NAME - 闪回查询(
AS OF TIMESTAMP)需要额外FLASHBACK对象权限,仅SELECT不够
真正麻烦的从来不是授权语句怎么写,而是你得同时对齐:schema 存在性、对象类型覆盖、备库执行位置、连接权限、SQL 写法、以及是否要支持闪回——少一个环,整个只读链就断在生产环境里。











