必须用OracleTypes.CURSOR显式注册每个REF CURSOR参数,不可用Types.OTHER或不存在的Types.REF_CURSOR;第一个游标用getResultSet()获取,其余须getObject()强转为ResultSet,索引从1开始且顺序严格对应,否则报ORA-01006或返回null。

必须用 OracleTypes.CURSOR 显式注册,不能用 Types.OTHER
Oracle JDBC 驱动不识别 java.sql.Types.REF_CURSOR(该常量根本不存在),也不接受 Types.OTHER 作为多游标场景的通用解。一旦注册错类型,getObject() 返回 null,后续调用 next() 直接抛 NullPointerException,且不报任何类型错误。
- 正确导入:
import oracle.jdbc.OracleTypes;,不是java.sql.Types - 注册写法:
cs.registerOutParameter(2, OracleTypes.CURSOR),索引从 1 开始,严格对应 SQL 中?位置 - 函数返回游标时,只允许
SYS_REFCURSOR类型;包内自定义的REF CURSOR(如pkg.my_cursor)JDBC 无法识别,会报invalid name pattern
getResultSet() 和 getObject() 的分工不能颠倒
第一个注册为 OracleTypes.CURSOR 的参数,必须用 getResultSet() 获取;第二个及以后的,必须用 getObject(idx) 强转为 ResultSet。混用或顺序错乱会导致 ORA-01006 或空结果。
- 执行
cs.execute()后,仅第一个游标被绑定到内部句柄,getResultSet()只能调一次,重复调返回null - 第二个游标:用
(ResultSet) cs.getObject(2),注意索引和注册顺序完全一致 - 别用已废弃的
getCursor()——它返回的是oracle.jdbc.driver.OracleResultSetImpl,不是标准接口,在 ojdbc8+ 中行为不稳定
字段名大小写、资源关闭、fetchSize 这三处最容易漏
Oracle 默认把未加双引号的列名转成大写,而 JDBC 按字面匹配。没关 ResultSet 会导致连接池卡死;不设 fetchSize 读百万行可能 OOM。
- 查
SELECT user_name FROM t,Java 必须写rs.getString("USER_NAME"),写"user_name"返回null - 每个
ResultSet必须显式close(),推荐用try (ResultSet rs = (ResultSet) cs.getObject(2)) { ... } - 大数据量时,在
execute()前加cs.setFetchSize(1000),避免默认拉取 10 行引发频繁网络往返和内存压力
多个游标要按顺序获取、反向关闭
每个 ResultSet 对应一个独立的服务器端游标资源,JDBC 不自动级联释放。只关 CallableStatement 不等于关了所有游标。
立即学习“Java免费学习笔记(深入)”;
- 获取顺序:先
rs1 = cs.getResultSet(),再rs2 = (ResultSet) cs.getObject(2),再rs3 = (ResultSet) cs.getObject(3) - 关闭顺序:建议反向,
rs3.close(); rs2.close(); rs1.close(); cs.close();,防止异常打断后续关闭 - 不要在 PL/SQL 里手动
CLOSE p_cursor——JDBC 会接管生命周期;否则可能报ORA-01001: invalid cursor
ResultSet 没关,就可能触发 ORA-01000: maximum open cursors exceeded,而且这个错误往往延迟出现,排查成本高。


















