You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:27:57