必须用 OracleTypes.CURSOR 显式注册每个 OUT 游标参数,第一个用 getResultSet() 获取,其余须 getObject() 强转为 ResultSet;注册时索引从 1 开始,且必须导入 oracle.jdbc.OracleTypes,不可用 Types.OTHER 或不存在的 Types.REF_CURSOR。
必须用 oracletypes.cursor 显式注册每个 out 参数,且第一个游标用 getresultset()、其余必须用 getobject() 强转为 resultset ——漏掉任一环节都会报 ora-01006、ora-01000 或返回 null。
注册多个 REF CURSOR 时不能用 Types.OTHER 或 Types.REF_CURSOR
Oracle JDBC 驱动不识别标准 JDBC 的 Types.REF_CURSOR(该常量在 java.sql.Types 中根本不存在),也不推荐用 Types.OTHER 注册多个游标(尤其在函数调用场景下可能部分生效,但存储过程多游标场景中大概率失败)。必须使用 Oracle 自己的类型常量:
-
stmt.registerOutParameter(1, OracleTypes.CURSOR)—— 第一个游标参数(索引从 1 开始) -
stmt.registerOutParameter(2, OracleTypes.CURSOR)—— 第二个游标参数 - 确保导入的是
oracle.jdbc.OracleTypes,不是java.sql.Types - 如果用错类或常量,
getObject()会返回null,且不抛异常,只在后续next()时报NullPointerException
获取 ResultSet:第一个用 getResultSet(),第二个起必须 getObject() + 强转
执行 execute() 后,JDBC 驱动只把第一个注册为 OracleTypes.CURSOR 的参数映射为内部结果集句柄,并绑定到 getResultSet();其余游标需显式取出:
-
ResultSet rs1 = stmt.getResultSet()—— 只能调一次,重复调返回null -
ResultSet rs2 = (ResultSet) stmt.getObject(2)—— 注意索引与注册顺序严格一致 ResultSet rs3 = (ResultSet) stmt.getObject(3)- 别用
getCursor():该方法是 Oracle 旧版特有 API,已标记为 deprecated,且返回类型非标准java.sql.ResultSet,在 ojdbc8+ 中行为不稳定 - 强转安全:只要注册正确,
getObject()返回的是oracle.jdbc.driver.OracleResultSetImpl,它实现了java.sql.ResultSet接口
包内过程 vs 函数:调用语法和参数位置完全不同
Oracle 包里的过程(PROCEDURE)和函数(FUNCTION)在 JDBC 调用时结构差异极大,混用必错:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 调包内过程(如
pkg.test_proc(?, ?)):
SQL 模板为{call pkg.test_proc(?, ?)},所有参数都是 OUT 或 IN/OUT,按声明顺序注册和取值 - 调包内函数(如
pkg.get_data()返回SYS_REFCURSOR):
SQL 模板为{? = call pkg.get_data()},第一个?是函数返回值,必须注册为OracleTypes.CURSOR,之后才能用getResultSet() - 若函数还有其他 IN 参数(如
{? = call pkg.get_data(?)}),则registerOutParameter(1, OracleTypes.CURSOR),setString(2, "xxx"),再execute(),最后getResultSet() - 切勿对函数用
getObject(1)—— 它返回的是游标句柄,不是结果集;也别对过程的第一个游标参数用getResultSet(),除非你确认它是第一个注册的CURSOR类型参数
容易被忽略的资源泄漏和兼容性坑
多个游标没关干净,轻则连接池耗尽,重则触发 ORA-01000: maximum open cursors exceeded;驱动版本不匹配也会让 getObject() 静默失败:
- 每个
ResultSet必须显式close(),哪怕只读了一行就异常了 —— 建议放在finally或 try-with-resources 中 - 用 ojdbc8.jar(对应 JDK 8+、Oracle 12c+),ojdbc6 对多游标支持不完整,
getObject()可能返回oracle.jdbc.driver.OracleResultSet而非接口实现,导致强转失败 - PL/SQL 包中定义的自定义游标类型(如
TYPE my_cursor IS REF CURSOR RETURN emp%ROWTYPE)无法被 JDBC 识别,必须统一用SYS_REFCURSOR - 如果存储过程里还混了其他 OUT 参数(比如
NUMBER或VARCHAR2),务必在调getResultSet()前先用getInt()/getString()取完 —— 否则getResultSet()可能返回null
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










