很多 DBA 都遇到过这种需求:某个账号平时需要完整权限,但到了割接、审计或问题排查阶段,希望它暂时只能查询,不能改数据,也不能建对象。
以前处理这类需求,常见做法是回收权限、切换角色,或者临时换一个只读账号。问题是权限一多,回收和恢复都容易漏。Oracle Database 23ai/26ai 给 PDB 本地用户增加了一个更直接的选择:把用户标记为 READ ONLY。
这不是把整个 PDB 改成只读,也不是重新设计一套授权。账号原来的权限仍在,只是当前被一道只读开关压住。恢复为 READ WRITE 后,原有权限继续生效。
一条命令,把现有账号切成只读
对已经存在的 PDB 本地用户,可以直接执行:
sql
alter user app_user read only;
需要恢复写入时,再执行:
sql
alter user app_user read write;
创建用户时也能直接指定只读状态:
sql
create user report_user
identified by "StrongPassword"
read only;
Oracle 官方文档对这个行为的描述很明确:只读用户连接到 PDB 后,会话的效果类似于数据库以只读模式打开,用户不能执行写操作。
这里有两个边界要先说清楚。
第一,这个语法针对的是 PDB 本地用户。它不是给 CDB 公共用户统一加一个只读标记。第二,PDB 本身仍然可以保持 READ WRITE,其他正常账号不受影响。限制只落在被标记的用户会话上。
权限还在,但写操作会被挡住
ORACLE-BASE 的测试很直观。测试账号被授予了 DB_DEVELOPER_ROLE,本来拥有不少对象创建权限。账号切换为只读以后,执行 CREATE TABLE 会返回:
text
ORA-28194: Can perform read operations only
INSERT、UPDATE 和 DELETE 同样会失败,普通 SELECT 则可以正常执行。
这个差别很重要。传统授权回答的是"这个用户有没有权限",只读标记回答的是"即使有权限,现在是否允许写"。Oracle 安全指南进一步说明,只读限制会覆盖已经授予的对象权限、系统权限和角色,包括 DBA 角色。
因此,排查时不要只看 DBA_SYS_PRIVS 或 DBA_ROLE_PRIVS。一个账号明明有写权限,却持续收到 ORA-28194,还要检查它是不是被设成了只读:
sql
select username,
read_only
from dba_users
where username = 'APP_USER';
READ_ONLY 为 YES,表示该用户的写权限当前被禁用;为 NO,表示用户处于读写状态。
PL/SQL 能执行,不等于能绕过限制
只读用户仍然可以执行 PL/SQL,前提是过程里没有发生写操作。
例如,一个只调用 DBMS_OUTPUT.PUT_LINE 的过程可以正常完成。另一个过程如果包含 INSERT,即使过程已经创建、用户也有执行权限,运行到写入语句时仍会触发 ORA-28194。
SELECT ... FOR UPDATE 也不行。它虽然以 SELECT 开头,但会锁定记录,为后续更新做准备,因此不属于纯读操作。
这说明只读限制不是简单拦截几种 SQL 关键字,而是约束会话是否产生写行为。对应用账号来说,这比逐项猜测哪些过程可能改数据更稳妥。不过,切换前仍要评估应用逻辑。有些健康检查、登录触发器、审计逻辑或业务查询会顺手写状态表,账号改成只读后可能直接报错。
这个功能适合用在哪里
最合适的场景,是账号平时需要写权限,但某个时间窗口内必须暂时冻结写入。
比如生产割接前,希望应用账号只能查询;安全调查期间,需要保留账号的访问能力,同时避免现场继续变化;报表或排障账号权限历史复杂,短时间内很难完成彻底梳理,也可以先用只读状态加一道保险。
相比回收几十项权限再逐条恢复,ALTER USER ... READ ONLY 的操作面更小,也更容易审计。它尤其适合短期状态切换,不必破坏原有授权结构。
但它不是权限治理的替代品。长期只需要查询的账号,仍应遵循最小权限原则,只授予必要的对象访问权限。只读标记也不会解决账号共享、口令管理、连接来源控制和敏感数据访问等问题。
还有一个操作细节:执行 ALTER USER 或 CREATE USER 的账号必须具备对应系统权限。生产环境中,谁可以切换只读状态、何时切换、如何恢复,都应该进入变更和审计流程,不能把它当成随手执行的开关。
DBA 上线前应做的检查
准备使用这个功能时,可以按下面的顺序验证:
- 确认数据库版本以及目标账号是 PDB 本地用户。
- 查询
DBA_USERS.READ_ONLY,记录切换前状态。 - 在测试环境验证普通查询、PL/SQL 调用、登录触发器和应用健康检查。
- 切换为只读后,分别测试
SELECT、DDL、DML 和SELECT ... FOR UPDATE。 - 明确恢复命令、执行人和回退窗口,再进入生产变更。
对 DBA 来说,这个功能的价值不在于语法有多复杂,恰恰是它足够简单。权限配置可以保持不动,只用一个可查询、可恢复的状态控制用户能不能写。遇到临时冻结账号写入的需求时,它比大范围回收权限更干净。