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

Spring JdbcTemplate无法获取含隐式游标存储过程结果的求助

解决Oracle存储过程通过dbms_sql.return_result返回多结果集的Spring JDBC调用问题

你的存储过程使用dbms_sql.return_result返回隐式结果集,而Spring JDBC的部分高层封装API默认只支持处理通过OUT参数声明的显式游标,因此出现异常或无结果的情况。以下是两种可行的解决方法:

方法1:使用JDBC原生API处理隐式结果集

绕过Spring的高层封装,直接用CallableStatement处理存储过程返回的隐式多结果集:

String callSql = "{call mystoredprocedure(?, ?)}";
try (Connection conn = jdbcTemplate.getDataSource().getConnection();
     CallableStatement cs = conn.prepareCall(callSql)) {
    // 设置参数
    cs.setString(1, "20025");
    cs.setString(2, "BATCH20025");
    
    // 执行存储过程,返回是否有结果集
    boolean hasResults = cs.execute();
    
    // 处理第一个结果集
    if (hasResults) {
        try (ResultSet rs1 = cs.getResultSet()) {
            BeanPropertyRowMapper<MyBean1> mapper1 = new BeanPropertyRowMapper<>(MyBean1.class);
            List<MyBean1> resultList1 = mapper1.mapRows(rs1);
            // 按需处理结果列表
        }
    }
    
    // 遍历剩余结果集
    while (cs.getMoreResults()) {
        try (ResultSet rs2 = cs.getResultSet()) {
            BeanPropertyRowMapper<MyBean2> mapper2 = new BeanPropertyRowMapper<>(MyBean2.class);
            List<MyBean2> resultList2 = mapper2.mapRows(rs2);
            // 按需处理结果列表
        }
    }
} catch (SQLException e) {
    // 异常处理逻辑
    e.printStackTrace();
}

方法2:修改存储过程为显式OUT游标返回(推荐,适配Spring JDBC封装)

如果允许修改存储过程,将隐式结果集改为显式OUT游标参数,这样Spring的SimpleJdbcCall可以正常识别并处理:

修改后的存储过程

create or replace procedure mystoredprocedure(
    userid VARCHAR, 
    batchno VARCHAR, 
    c1 out sys_refcursor, 
    c2 out sys_refcursor
) as 
begin
    open c1 for select * from table A;
    open c2 for select * from table B;
end;

使用SimpleJdbcCall调用

SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
        .withProcedureName("mystoredprocedure")
        .withoutProcedureColumnMetaDataAccess()
        .withNameBinding()
        .declareParameters(
                new SqlParameter("userid", Types.VARCHAR),
                new SqlParameter("batchno", Types.VARCHAR),
                new SqlOutParameter("c1", OracleTypes.CURSOR, new BeanPropertyRowMapper<>(MyBean1.class)),
                new SqlOutParameter("c2", OracleTypes.CURSOR, new BeanPropertyRowMapper<>(MyBean2.class))
        );

Map<String, Object> actualParams = new HashMap<>();
actualParams.put("userid", "20025");
actualParams.put("batchno", "BATCH20025");

// 执行并获取结果
Map<String, Object> results = jdbcCall.execute(actualParams);
List<MyBean1> list1 = (List<MyBean1>) results.get("c1");
List<MyBean2> list2 = (List<MyBean2>) results.get("c2");

原有三种方法失效原因说明

  • 方式1:JdbcTemplate.query仅适用于处理单结果集的SQL语句或存储过程,无法识别dbms_sql.return_result返回的隐式多结果集,因此抛出cannot perform fetch on a pl/sql statement : next异常。
  • 方式2:传统StoredProcedure类默认只处理通过OUT参数声明的显式游标,不支持dbms_sql.return_result的隐式结果集,因此无结果返回。
  • 方式3:SimpleJdbcCall的returningResultSet方法是绑定到存储过程的OUT游标参数的,但你的原存储过程未定义任何OUT游标,因此无法匹配到结果集,返回空Map。

内容的提问来源于stack exchange,提问作者Kannan Sundararaj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:00:03