Oracle JDBC驱动需显式注册SYS_REFCURSOR为Types.OTHER,执行前注册、执行后取结果,用getObject()获取ResultSet并手动close(),否则引发ORA-01000等错误。
默认情况下,OracleDriver 不会自动将 SYS_REFCURSOR 映射为 ResultSet,必须显式注册类型。不注册就调用 getResultSet() 会抛 SQLException: invalid column type 或返回 null。
关键操作是:在 CallableStatement 执行前,对每个 SYS_REFCURSOR 输出参数调用 registerOutParameter(int paramIndex, Types.OTHER),且驱动版本需 ≥ 12.1(推荐使用 ojdbc8.jar)。
Types.OTHER,不能用 Types.STRUCT 或 Types.JAVA_OBJECT
registerOutParameter
OUT 参数声明顺序一致拿到 CallableStatement 后,执行顺序错一步就会失败:先注册 → 再执行 → 最后取结果。常见错误是执行完才去注册,或注册后又调用 setXXX() 改变参数状态。
String sql = "{call my_pkg.get_data(?, ?)}";CallableStatement cs = conn.prepareCall(sql);cs.registerOutParameter(2, Types.OTHER); // 第2个参数是 SYS_REFCURSORcs.setString(1, "key");cs.execute(); // 必须 execute() 之后才能 getResultSet()ResultSet rs = (ResultSet) cs.getObject(2); // 推荐用 getObject(),不是 getResultSet()
cs.getObject(2) 比 cs.getResultSet() 更可靠;后者仅适用于最后一个 OUT 参数是 REF CURSOR 的场景cs.getResultSet(),会报 “statement not executed”INT),要在 execute() 后、取 ResultSet 前读取REF CURSOR 对应的 ResultSet 生命周期绑定到数据库游标,不及时关闭会导致 Oracle 端游标堆积、ORA-01000 错误,尤其在 HikariCP 或 Druid 连接池中表现明显。
rs.close(),不能依赖 try-with-resources 自动关闭 —— 因为 rs 是从 cs 拿出来的,不是直接创建的cs.close() 不会自动关闭其派生的 ResultSet,JDBC 规范明确要求手动关ConnectionCallback 手动管理,它不支持 REF CURSOR 自动释放存储过程可能因条件不满足返回 NULL 的 SYS_REFCURSOR,此时 getObject(2) 返回 null,而非空 ResultSet。直接调用 next() 会 NPE。
Object obj = cs.getObject(2);if (obj == null) {// 存储过程未打开游标,按无数据处理} else {ResultSet rs = (ResultSet) obj;while (rs.next()) { /* ... */ }rs.close();}
rs == null 判断,要先检查 getObject() 返回值OPEN refcur FOR NULL;,Java 端收到的就是 null
NullPointerException 而非返回 null,升级驱动可规避实际中最容易被忽略的是:REF CURSOR 的生命周期完全由 Oracle 控制,Java 层没有任何缓冲或延迟释放机制。一旦忘记 close(),问题往往在压测时才暴露,且日志里只显示游标耗尽,很难关联到具体哪段代码漏关。
小米路由器历史固件怎么删除(小米路由器历史固件删除方法)
小米路由器青春版mini潘多拉固件怎么升级的(小米路由器青春版mini潘多拉固件升级方法)
小米路由器青春版mini怎么恢复出厂(小米路由器青春版mini恢复出厂方法)
小米路由器青春版mini设置教程(小米路由器青春版mini如何设置)
小米路由器分享路由器什么意思啊(小米路由器分享路由器含义详解)
小米路由器默认ip进不去怎么办(小米路由器默认ip进不去解决方案)