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

如何为返回多个ResultSet的存储过程创建H2别名函数?

问题

我目前用H2别名函数模拟存储过程调用,处理返回单个ResultSet的存储过程时一切正常,但现在需要为返回两个ResultSet的存储过程创建别名函数,尝试返回List和SimpleResultSet[]都导致JDBC层报错,不清楚正确实现方式。

我的别名方法代码如下(需要返回两个ResultSet实例及其元数据):

public static ResultSet someMethodName(final Connection connection) throws SQLException {

  //Metadata for RS1
  final SimpleResultSet resultSet1 = new SimpleResultSet();
  resultSet1.addColumn("field_1", Types.VARCHAR, 10, 0);
  resultSet1.addColumn("field_2", Types.VARCHAR, 10, 0);

  //Metadata for rs2
  final SimpleResultSet resultSet2 = new SimpleResultSet();
  resultSet1.addColumn("field_1", Types.INTEGER, 10, 0);
  resultSet1.addColumn("field_2", Types.INTEGER, 10, 0); // 注意:原代码此处写错,应为resultSet2

  if (connection.getMetaData().getURL().equals("jdbc:columnlist:connection")) {
    //How do you return the two ResultSet instances?
  }

   //How do you return the two ResultSet instances?
}

另外,我在Sybase中调用实际存储过程并处理结果集的代码运行正常,参考如下:

final SqlParameter[] parameters = new SqlParameter[]{
        new SqlReturnResultSet("result_1", (rs) -> {
          listA.add(ObjectA.builder()
              .field1(rs.getString("field_1"))
              .field2(rs.getString("field_2"))
              .build());
        }),
        new SqlReturnResultSet("result_2", (rs) -> {
          listB.add(ObjectB.builder()
              .field1((Integer) rs.getObject("field_1"))
              .field2((Integer) rs.getObject("field_2"))
              .build());
        }),
    };

final List<ObjectA> listA = new ArrayList<>();
final List<ObjectB> listB = new ArrayList<>();

return new SimpleJdbcCall(jdbcTemplate)
    .withSchemaName("dbo")
    .withProcedureName(spName)
    .withoutProcedureColumnMetaDataAccess()
    .declareParameters(parameters)
    .execute(Arrays.stream(parameters)
        .filter(SqlParameterValue.class::isInstance)
        .map(SqlParameterValue.class::cast)
        .collect(Collectors.toMap(SqlParameterValue::getName, SqlParameterValue::getValue)));

请问如何在H2别名方法中正确返回这两个ResultSet实例?

解决方案

H2中返回多个ResultSet的别名函数,需要使用H2提供的**org.h2.tools.MultiResultSet**类——它是java.sql.ResultSet的子类,专门用于封装多个结果集。直接返回List或数组会被JDBC驱动拒绝,因为H2只识别特定的ResultSet实现。

修改后的别名方法代码如下:

import org.h2.tools.MultiResultSet;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import org.h2.result.SimpleResultSet;

public static ResultSet someMethodName(final Connection connection) throws SQLException {

  // 初始化第一个结果集(修正原代码的列添加错误)
  final SimpleResultSet resultSet1 = new SimpleResultSet();
  resultSet1.addColumn("field_1", Types.VARCHAR, 10, 0);
  resultSet1.addColumn("field_2", Types.VARCHAR, 10, 0);
  // 可在此添加数据行:resultSet1.addRow("val1", "val2");

  // 初始化第二个结果集(修正原代码的对象引用错误)
  final SimpleResultSet resultSet2 = new SimpleResultSet();
  resultSet2.addColumn("field_1", Types.INTEGER, 10, 0);
  resultSet2.addColumn("field_2", Types.INTEGER, 10, 0);
  // 可在此添加数据行:resultSet2.addRow(1, 2);

  // 处理H2的元数据请求(特殊连接用于获取结果集结构)
  if (connection.getMetaData().getURL().equals("jdbc:columnlist:connection")) {
    return MultiResultSet.create(resultSet1, resultSet2);
  }

  // 正常返回封装后的多结果集
  return MultiResultSet.create(resultSet1, resultSet2);
}

关键说明:

  1. 修复原代码bug:原代码中给第二个结果集添加列时错误操作了resultSet1,会导致第一个结果集出现重复列,必须改为操作resultSet2。
  2. 使用MultiResultSet封装:MultiResultSet.create()方法可接收多个ResultSet实例,将其封装为H2 JDBC驱动可识别的多结果集对象。
  3. 元数据分支兼容:当H2通过jdbc:columnlist:connection请求元数据时,同样需要返回包含两个结果集元数据的MultiResultSet,否则会导致元数据获取失败。

采用这种方式后,你现有的Spring SimpleJdbcCall代码无需修改,即可像在Sybase中一样正常处理两个结果集。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 16:05:12