ora-01031 根本原因是 pl/sql 中 authid definer 模式下角色权限不生效,仅认显式授予的系统/对象权限;排查应先查 session_roles 和 session_privs 确认实际生效权限。

ORA-01031 在存储过程中报出,基本不是账号密码错,而是权限校验时机与执行上下文不匹配——尤其是用 EXECUTE IMMEDIATE 执行 DDL 或访问其他 schema 对象时。
为什么直接建表成功,但存储过程里就报 ORA-01031?
因为 Oracle 默认用 AUTHID DEFINER 模式:编译时就检查定义者(即过程属主)是否拥有底层权限,且**角色权限(如 DBA、RESOURCE)完全不生效**。哪怕你手动能 CREATE TABLE,只要没被显式授予 CREATE TABLE 或 CREATE ANY TABLE,编译或运行都会失败。
- 直接 SQL 是会话级执行,角色权限(如 SET ROLE ALL 后)可用
- PL/SQL 过程中角色权限默认不可见,只认
SESSION_PRIVS里列出的直授权限 - 常见陷阱:查
DBA_ROLE_PRIVS看到有 DBA,但SELECT * FROM SESSION_PRIVS里没有CREATE TABLE
改用 AUTHID CURRENT_USER 能解决问题吗?
能绕过编译时校验,把权限检查推迟到运行时,并允许使用调用者已启用的角色权限——但前提是调用者会话里 SESSION_ROLES 非空。
- 必须在调用前执行
SET ROLE ALL(无密码角色)或SET ROLE role_name IDENTIFIED BY 'pwd' - JDBC / cx_Oracle 连接后不会自动启用角色,需在应用代码里显式执行
SET ROLE语句 - 某些场景(如 DBMS_SCHEDULER JOB、代理连接)仍可能丢失角色上下文,导致运行时报错
-
AUTHID CURRENT_USER不解决对象权限缺失问题,比如SELECT * FROM hr.employees还是需要GRANT SELECT ON hr.employees TO your_user
最稳的授权方式是什么?
绕过角色,直接授予系统权限和对象权限。这是生产环境可审计、最小粒度可控的做法。
- 建表/删表:
GRANT CREATE TABLE TO your_user(非CREATE ANY TABLE) - 跨 schema 访问:
GRANT SELECT ON hr.employees TO your_user,不能只靠角色 - 查数据字典视图:
GRANT SELECT_CATALOG_ROLE TO your_user不够,得GRANT SELECT ON SYS.DBA_USERS TO your_user或更细粒度授权 - 别漏配套权限:
CREATE SESSION和表空间配额(UNLIMITED TABLESPACE或ALTER USER your_user QUOTA UNLIMITED ON users)
排查时第一步该看什么?
登录出错会话,立刻查两个视图——它们才是当前真实权限快照,比任何 DBA_* 视图都可靠。
-
SELECT * FROM SESSION_ROLES:返回空?说明角色没启用,SET ROLE ALL是必须动作 -
SELECT * FROM SESSION_PRIVS:里面没有你要的操作对应权限(如CREATE TABLE),就说明直授缺失,别再查角色了 - 如果是跨 schema 动态 SQL,再补查
SELECT * FROM SESSION_TAB_PRIVS WHERE TABLE_NAME = 'EMPLOYEES'确认对象权限是否落地
真正卡住人的地方,往往不是“没授权”,而是“授权了但没激活”,或者“激活了但在 PL/SQL 里不可见”。每次遇到 ORA-01031,先跑这两条 SELECT,比反复 GRANT 更省时间。











