Oracle 只读视图与同义词:建视图、授权、回收的完整流程
想让某个用户只能查询、不能改动数据,还要挡住敏感列,Oracle 里最顺手的组合是「视图 + 只读授权」:把想暴露的列收进视图,再把视图的 SELECT 权限授出去,基表对用户完全不可见。同义词在这之上再加一层别名,让跨 schema 的访问更省事。
这篇按场景组织:要给用户只读访问怎么做、要回收权限怎么做、要简化对象名怎么做,最后给一份语句速查表。所有 SQL 为 Oracle 通用语法(11g 及以上适用)。
注:Oracle 无法容器化快速验证,本文 SQL 未在真实实例实跑,语法以 Oracle Database SQL Language Reference 为准;执行前请在测试库演练。
场景一:给用户只读访问(建表 → 建视图 → 授权)
这是最完整的链路,三步走完得到一个”能查、能查到的列受限、不能改”的账号。
准备示例表
先建一张 employees 基础表并塞两条数据:
1 | CREATE TABLE employees ( |
注意表里有 salary、phone_number 这类敏感列——下一步建视图时会故意把它们排除在外。
创建视图:决定暴露哪些列
视图 employee_overview 只保留工号、姓名和邮箱:
1 | CREATE VIEW employee_overview AS |
视图本身不存数据,只是一条封装好的查询。敏感列不在视图的 SELECT 列表里,用户通过视图就永远碰不到——这是列级隔离的标准做法,比在应用层过滤可靠得多。顺带一提,视图的 WHERE 子句也能做粗粒度的行级过滤(比如只暴露 department_id = 10 的行);要按调用者身份动态控制的行级安全,Oracle 的对应机制是 VPD(DBMS_RLS 包),不在本文展开。
建只读用户并授权
1 | -- 创建用户 |
GRANT SELECT 只授了查询,没有 INSERT、UPDATE、DELETE,这就是”只读”的全部来源。注意授权对象是视图不是基表——基表 employees 的权限一点都没给出去。
用这个账号登录验证:
1 | CONNECT readonly_user/password@your_database |
验证标准:视图查询成功、基表报 ORA-00942(用户根本”看不到”这张表)、写操作报 ORA-01031。三个都符合预期,只读隔离才算生效。
场景二:回收权限
权限收回来同样一条语句,立即生效:
1 | REVOKE SELECT ON employee_overview FROM readonly_user; |
回收后该用户再查视图会报 ORA-01031。要彻底清理账号(连登录能力一起收回):
1 | REVOKE CONNECT FROM readonly_user; |
场景三:用同义词简化对象名
同义词(Synonym)是数据库对象的别名。给视图配一个更短的通用名字,用户访问时不用关心视图建在哪个 schema 下:
1 | -- 创建同义词 emp_view 指向视图 employee_overview |
之后 readonly_user 直接查同义词即可:
1 | SELECT * FROM emp_view; |
跨 schema 访问时,同义词要指向带 schema 前缀的对象:
1 | CREATE SYNONYM emp_view FOR hr_schema.employee_overview; |
这样应用代码里写 emp_view,底层对象在哪个 schema、叫什么名字,对应用完全透明。
公用同义词 vs 私有同义词
| 类型 | 创建语句 | 可见范围 | 所需权限 |
|---|---|---|---|
| 私有同义词 | CREATE SYNONYM emp_view FOR ... |
仅创建者(及被授权用户) | CREATE SYNONYM |
| 公用同义词 | CREATE PUBLIC SYNONYM emp_view FOR ... |
数据库内所有用户 | CREATE PUBLIC SYNONYM(通常 DBA 才有) |
原文写的是”登录为 DBA 用户创建公用同义词”,但语句用的是 CREATE SYNONYM(私有)——两者不一致。要建公用同义词必须加 PUBLIC 关键字;不加就是私有同义词,只有创建者能用。实际场景中,给单个只读用户用的话,在 readonly_user 名下建私有同义词更合适(权限收敛,不污染全局命名空间):
1 | -- 以 readonly_user 身份(或 DBA 代建) |
不需要时删除同义词:
1 | DROP SYNONYM emp_view; -- 私有 |
语句速查表
| 目的 | 语句 |
|---|---|
| 建视图(列级隔离) | CREATE VIEW v AS SELECT 需要的列 FROM 基表; |
| 建用户 | CREATE USER u IDENTIFIED BY pwd; |
| 给登录能力 | GRANT CONNECT TO u; |
| 给只读权限 | GRANT SELECT ON v TO u; |
| 回收只读权限 | REVOKE SELECT ON v FROM u; |
| 删用户 | DROP USER u [CASCADE]; |
| 建私有同义词 | CREATE SYNONYM s FOR [schema.]对象; |
| 建公用同义词 | CREATE PUBLIC SYNONYM s FOR [schema.]对象; |
| 删同义词 | DROP [PUBLIC] SYNONYM s; |
| 查用户有哪些权限 | SELECT * FROM dba_tab_privs WHERE grantee='U'; |
| 查同义词映射 | SELECT * FROM dba_synonyms WHERE synonym_name='S'; |
同义词的注意事项与优缺点
用同义词前先知道它的边界:
- 命名冲突:同一命名空间内,同义词不能和表、视图等其他对象重名;公用同义词与某用户的私有对象重名时,私有对象优先(解析顺序:本 schema 对象 → 私有同义词 → 公用同义词)。
- 权限要求:创建同义词不需要对目标对象有权限,但使用时必须有——同义词只是别名,不做授权。给 readonly_user 建了指向某视图的同义词,但没 GRANT SELECT,查起来照样 ORA-01031。这是最常见的误解。
- 跨库引用:同义词指向远程数据库对象时,要先建 DATABASE LINK,同义词 FOR 子句里带
@dblink,并确认链接的账号权限。
它的价值也很清楚:
- 简化访问:多个用户、多个 schema 之间共享对象时,一个短名字就能访问。
- 灵活换绑:底层对象迁移(换 schema、换表名)时,重建同义词指向新对象即可,应用代码一行不改。
- 命名一致:开发/测试/生产环境用统一命名,减少环境差异带来的维护成本。
代价是同义词数量大了以后管理会变复杂(谁指向谁要靠查 dba_synonyms),且不合理的映射可能引入安全风险——公用同义词等于给全库用户暴露了一个入口名,需要有人盯着。
注意事项
- 视图 +
GRANT SELECT是只读隔离的核心,同义词只是”起名”,不承担权限职责;漏了 GRANT 只建同义词,用户依然访问不了。 GRANT CONNECT在 Oracle 中权限已大幅收缩(10g 之后只剩 CREATE SESSION),别指望它带来别的权限;要建同义词需额外GRANT CREATE SYNONYM。- 视图定义变更(增删列)后,依赖它的同义词和应用代码要同步核对;视图失效时同义词查询会报 ORA-04063。
- 敏感数据隔离要在视图层做(不 SELECT 该列),不要指望”授了 SELECT 但应用不显示”——权限层面能查到的数据,就等于暴露了。
- 授权/回收都建议记录在变更单里,定期用
dba_tab_privs审一遍谁对哪些视图有权限。
小结
视图负责”暴露哪些数据”,只读授权负责”能对暴露的数据做什么”,同义词负责”叫什么名字”——三者组合起来,就是一套对应用透明、对基表零暴露的只读访问方案。权限的授予与回收都是单条语句,随业务随时调整。
本文由作者 2020-2024 年间的 CSDN 博客文章重构而来,原发布于 CSDN。