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
相关产品推荐
相关产品推荐

