必须用out参数声明sys_refcursor并在begin块中open for赋值;声明为in/in out、在声明区open或用select into均报错,jdbc调用须registeroutparameter为types.other。

必须用 OUT 参数声明 SYS_REFCURSOR,并在 BEGIN 块里用 OPEN ... FOR 赋值——漏掉 OUT、写成 IN OUT、或在声明区就 OPEN,都会报错。
参数方向只能是 OUT,不能是 IN 或 IN OUT
SYS_REFCURSOR 是单向输出通道,不是双向数据容器。Oracle 要求它必须作为 OUT 参数传递,否则编译失败:
-
PLS-00363: expression 'p_result' cannot be used as an assignment target—— 如果声明成IN或没写方向 -
ORA-06550 + PLS-00382—— 如果 Java 端用Types.RESULT_SET注册,但 Oracle 驱动只认Types.OTHER - 即使过程能编译,JDBC 也拿不到结果集,因为驱动不支持非
OUT方向的游标绑定
OPEN 必须在 BEGIN 块内,不能放在声明区
OPEN p_result FOR SELECT ... 是运行时动作,不是声明。PL/SQL 不允许在变量声明区执行语句:
- 放错位置会直接报
PLS-00103:Encountered the symbol "OPEN" - 也不能用
SELECT ... INTO替代 —— 那只能赋单行,而SYS_REFCURSOR是为多行设计的 - 动态 SQL 可以用
EXECUTE IMMEDIATE ... USING配合OPEN ... FOR,但绑定变量必须在FOR后显式写出,不能拼字符串
Java 调用时 registerOutParameter 必须用 Types.OTHER
JDBC 层面对 SYS_REFCURSOR 的映射是固定的,不是靠猜测:
- 必须写
stmt.registerOutParameter(2, Types.OTHER),写成Types.RESULT_SET会抛SQLException: Invalid column type - 获取结果集只能用
stmt.getResultSet(),不能用getObject()或getCursor() - 结果集必须在同一个数据库连接内消费完,否则连接关闭后游标自动失效,再 fetch 就触发
ORA-01001: invalid cursor
别和临时表逻辑混在一起
有人在过程开头先 INSERT INTO temp_table ... 再 OPEN p_result FOR SELECT FROM temp_table,这看似合理,实则埋雷:
- 如果临时表是
ON COMMIT DELETE ROWS,事务一提交,游标打开时表已空 - 如果是
ON COMMIT PRESERVE ROWS,不同会话可能看到彼此残留数据,尤其在连接池场景下 -
SYS_REFCURSOR本意是“把查询权交出去”,不是“把中间结果存下来”——直接OPEN FOR SELECT ... JOIN ... WHERE ...更安全、更可读、也更容易优化
真正容易被忽略的是:游标打开那一刻,SQL 就已编译并锁定执行计划;后续表结构变更、统计信息刷新、甚至绑定变量窥探行为,都不会影响这次调用——这点在调试性能问题时经常被当成黑盒绕过去。










