open for 必须配合 sys_refcursor 或显式声明的 ref cursor 类型变量使用;普通显式游标不支持,否则报 pls-00382 错误。

OPEN FOR 必须配合 SYS_REFCURSOR 类型变量使用
直接写 OPEN my_cursor FOR ... 会报错,除非 my_cursor 是 SYS_REFCURSOR 或显式声明的 REF CURSOR 类型。普通显式游标(如 CURSOR c IS SELECT ...)不支持 OPEN FOR,它只能在声明时绑定固定查询。
常见错误现象:PLS-00382: expression is of wrong type,往往是因为把字符串赋值给了非 REF CURSOR 类型的变量,比如误写成 my_cursor := 'SELECT ...';。
-
SYS_REFCURSOR是 Oracle 内置弱类型,开箱即用,适合快速返回结果集 - 若需编译期校验列结构,应自定义强类型:
TYPE emp_rc IS REF CURSOR RETURN emp%ROWTYPE; - 声明位置必须在
DECLARE或存储过程参数中,不能在包规范里直接声明为全局变量(会报PLS-00103)
动态 SQL 的 OPEN FOR 语法必须用 USING 传参,不能拼接
想让查询条件可变,必须用 OPEN cur FOR 'SELECT ... WHERE col = :1' USING val;。字符串拼接(如 'WHERE id = ' || p_id)不仅易出错,更会导致 SQL 注入和隐式类型转换失败。
绑定变量个数与 USING 参数顺序必须严格一致——:1 对应第一个参数,:2 对应第二个,不支持命名绑定(:id 在动态 SQL 中无效)。
- 支持任意数据类型:数值、字符串、日期、对象、集合都可通过
USING安全传递 - SQL 字符串可用
VARCHAR2变量承载,但长度不能超 32767 字节(否则触发ORA-06502) - 如果 SQL 含子查询或 WITH 子句,只要语法合法,
OPEN FOR照样支持
存储过程里不能 FETCH 或 CLOSE SYS_REFCURSOR 输出参数
一旦把 SYS_REFCURSOR 声明为 OUT 参数并 OPEN,它的生命周期就移交给了调用方。你在过程里调 FETCH 或 CLOSE,轻则报 ORA-01001: invalid cursor,重则导致调用方拿到空结果或连接卡死。
典型翻车点:有人在匿名块里先 OPEN 游标,再 FETCH 一行验证,最后 RETURN——这完全违背了 REF CURSOR 的设计意图,它不是用来“取数据”的,是用来“交句柄”的。
- 输出参数必须是
OUT(不能是IN OUT),且OPEN必须在BEGIN块内完成 - 调用方(JDBC / PL/SQL Developer / 匿名块)负责
FETCH和CLOSE;未关闭会导致 PGA 内存泄漏 - 函数返回 REF CURSOR 时,也禁止在函数体内
CLOSE,否则调用方拿到的是已关闭游标
JDBC 调用时 registerOutParameter 必须用 OracleTypes.CURSOR
Java 端若用 Types.OTHER 或 Types.JAVA_OBJECT 注册 SYS_REFCURSOR 输出参数,驱动根本识别不了,抛 java.sql.SQLException: Invalid column type。
字段名大小写问题高频发生:Oracle 默认把未加双引号的列名转成大写,而 JDBC ResultSet.getString("name") 是严格区分大小写的。写成 "NAME" 才能取到值,或者建表/查询时统一用双引号保留小写。
- Spring JDBC 中必须用
SqlOutParameter("p_cur", OracleTypes.CURSOR),不能用Types.OTHER - 获取结果集用
cs.getCursor(2)比(ResultSet) cs.getObject(2)更安全、语义更清晰 - 务必用 try-with-resources 包裹
ResultSet,否则连接池里的物理连接可能因游标未关而被长期占用
AUTONOMOUS_TRANSACTION)传递,也不能在 DBMS_SCHEDULER 作业中直接返回给外部客户端——它只活在当前服务器进程的 PGA 里。











