CREATE CONTEXT 必须指定 USING 包,否则上下文为空壳且 SYS_CONTEXT 查不到值;包需存在、可执行,并封装 DBMS_SESSION.SET_CONTEXT 调用以绕过权限限制。
CREATE CONTEXT 为什么必须指定 USING 包?
不指定 using 包,上下文就只是个空壳——sys_context 查不到任何值。oracle 要求上下文必须绑定到一个 pl/sql 包,由该包里的过程负责设置属性(dbms_session.set_context),否则上下文无法被安全写入。
- 创建时漏掉
USING,语句能执行成功,但后续调用DBMS_SESSION.SET_CONTEXT会报ORA-01925: maximum number of enabled roles exceeded或静默失败(取决于权限) - 包必须存在、编译成功,且拥有
EXECUTE权限;建议用专用包(如ctx_pkg),别直接用sys.dbms_session - 上下文名称和命名空间名区分大小写,但
SYS_CONTEXT第二个参数(属性名)不区分大小写
SYS_CONTEXT 查询不到值的三个常见原因
SYS_CONTEXT 返回 NULL 不代表没设,大概率是上下文没在当前会话生效,或属性名拼错。
- 上下文只对「创建它的会话」或「显式调用
SET_CONTEXT的会话」有效;连接池复用时容易误以为“已设置”,实际是新会话 - 属性名必须和
SET_CONTEXT中传入的完全一致(忽略大小写,但空格、下划线不能错),比如设的是'USER_ID',查'user_id'可以,查'userid'就不行 - 上下文默认作用域是
SESSION,如果用了ACCESSED GLOBALLY却没配共享内存或 RAC 环境,也会查不到
SET_CONTEXT 必须在包内调用,不能裸写在匿名块里
直接在 SQL*Plus 或应用代码里执行 DBMS_SESSION.SET_CONTEXT 会报 ORA-01031: insufficient privileges,除非用户有 ADMINISTER DATABASE TRIGGER(不推荐)。
- 必须把
SET_CONTEXT封装进USING指定的包中,且该包用AUTHID DEFINER(默认),才能绕过权限检查 - 包过程应校验输入,比如过滤空值、截断超长字符串(上下文属性值最大 4000 字节),否则可能触发隐式转换或截断无提示
- 示例安全写法:
CREATE OR REPLACE PACKAGE ctx_pkg AUTHID DEFINER AS PROCEDURE set_user_info(p_user_id VARCHAR2); END;
CREATE OR REPLACE PACKAGE BODY ctx_pkg AS PROCEDURE set_user_info(p_user_id VARCHAR2) IS BEGIN IF p_user_id IS NOT NULL THEN DBMS_SESSION.SET_CONTEXT('MY_APP_CTX', 'USER_ID', SUBSTR(p_user_id, 1, 200)); END IF; END; END;
应用里怎么安全传参给 SET_CONTEXT?
Web 应用或 JDBC 连接通常靠登录后立刻调用一次包过程来初始化上下文,这里最容易出问题的是事务边界和连接生命周期。
- 不要在事务中间调用;
SET_CONTEXT是会话级操作,跟事务无关,但若放在COMMIT后再调,可能因连接被归还池而丢失 - JDBC 中避免用
CallableStatement直接调包过程后立即关闭——有些驱动会隐式 commit 或 reset session,导致上下文清空 - 如果用 Oracle UCP 或 HikariCP,确认连接池配置了
connection-validation-timeout和valid-connection-checker-class-name,否则旧上下文可能残留到新请求
CREATE CONTEXT 语法全对,只要包没权限、调用不在包里、或者连接被复用却忘了重设,SYS_CONTEXT 就永远返回 NULL。










