使用Hibernate调用带游标参数的Oracle存储过程报错求助
解决Oracle带游标参数的存储过程调用问题
首先,你的错误根源有两个:一是EXEC是SQL*Plus的专属命令,并不是标准SQL语法,直接在Hibernate里执行会触发ORA-00900错误;二是你确实没有传递存储过程要求的第二个IN OUT游标参数。下面分两种场景给出正确的调用方式:
一、在SQL Developer中测试存储过程
要调用带游标参数的存储过程,你需要用PL/SQL块来处理游标变量,示例代码如下:
DECLARE -- 声明与包中定义一致的游标变量 v_status_cursor TESTPACKAGE.STATUSCURSOR; v_input_id VARCHAR2(50) := 'testId'; -- 根据你游标实际返回的列定义接收变量,这里假设返回两列:状态码和状态描述 v_status_code VARCHAR2(20); v_status_desc VARCHAR2(100); BEGIN -- 调用存储过程,传入输入参数和游标变量 TESTPACKAGE.TestProcedure(v_input_id, v_status_cursor); -- 遍历游标获取结果 LOOP FETCH v_status_cursor INTO v_status_code, v_status_desc; EXIT WHEN v_status_cursor%NOTFOUND; -- 打印结果到控制台 DBMS_OUTPUT.PUT_LINE('状态码: ' || v_status_code || ' | 状态描述: ' || v_status_desc); END LOOP; -- 关闭游标 CLOSE v_status_cursor; END; /
执行这段代码前,记得打开SQL Developer的DBMS输出(View → DBMS Output → 添加连接),这样就能看到游标返回的数据。
二、在Hibernate中调用存储过程
推荐两种可靠的方式,根据你的Hibernate版本选择:
方式1:使用StoredProcedureQuery(Hibernate 5及以上版本推荐)
这是Hibernate官方推荐的存储过程调用方式,语法更简洁,无需手动处理ResultSet:
// 创建存储过程查询对象 StoredProcedureQuery spQuery = session.createStoredProcedureQuery("TESTPACKAGE.TestProcedure"); // 注册输入参数,对应存储过程的cId参数 spQuery.registerStoredProcedureParameter("cId", String.class, ParameterMode.IN); spQuery.setParameter("cId", "testId"); // 注册IN OUT游标参数,对应StatusCursonVal参数 spQuery.registerStoredProcedureParameter("StatusCursonVal", void.class, ParameterMode.REF_CURSOR); // 执行并获取结果列表,每个元素是游标返回的一行数据(Object数组) List<Object[]> resultList = spQuery.getResultList(); // 遍历结果处理数据 for (Object[] row : resultList) { String statusCode = (String) row[0]; String statusDesc = (String) row[1]; // 这里添加你的业务逻辑 }
方式2:使用createSQLQuery(兼容旧版本Hibernate)
如果你的Hibernate版本较低,可以用原生SQL调用,需要手动处理游标结果:
// 使用标准的JDBC调用语法:{call 存储过程名(?, ?)} String sql = "{call TESTPACKAGE.TestProcedure(?, ?)}"; SQLQuery sqlQuery = session.createSQLQuery(sql); // 设置第一个输入参数 sqlQuery.setString(0, "testId"); // 注册第二个游标输出参数,需要导入oracle.jdbc.OracleTypes sqlQuery.registerOutParameter(1, OracleTypes.CURSOR); // 执行调用 sqlQuery.execute(); // 获取游标对应的ResultSet ResultSet rs = (ResultSet) sqlQuery.getOutputParameterValue(1); // 遍历ResultSet封装结果 List<Object[]> resultList = new ArrayList<>(); while (rs.next()) { Object[] row = new Object[2]; row[0] = rs.getString(1); // 对应游标第一列 row[1] = rs.getString(2); // 对应游标第二列 resultList.add(row); } // 关闭ResultSet(注意:Hibernate会话关闭时会自动处理,但手动关闭更安全) rs.close();
关键注意事项
- 永远不要在JDBC/Hibernate中使用
EXEC命令,它只适用于SQL*Plus或SQL Developer的命令行界面,标准SQL调用存储过程必须用{call ...}语法。 - 对于IN OUT或OUT类型的游标参数,必须显式注册,无论是在PL/SQL块还是Java代码中都不能省略。
- 如果游标返回的是实体对象,你还可以在
StoredProcedureQuery中使用addEntity()方法直接映射到实体类,简化结果处理。
内容的提问来源于stack exchange,提问作者Anirban
相关产品推荐
相关产品推荐

