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

返回ResultSet后触发‘结果集已关闭’异常,如何兼顾取数与关闭连接?

解决ResultSet被提前关闭的问题

问题根源

你遇到的问题确实是因为try-with-resources会在try块执行完毕后自动关闭CallableStatement和Connection,而ResultSet的生命周期依赖于创建它的Statement,一旦Statement关闭,ResultSet也会被强制关闭,导致后续读取数据时抛出异常。

最小改动解决方案

核心思路是不要直接返回ResultSet,而是在方法内部将ResultSet中的数据读取到内存集合中,再返回集合。这样数据库资源可以在方法内安全关闭,调用方操作的是内存中的数据,不受数据库资源生命周期影响。

方案1:返回实体类集合(推荐,类型安全)

假设你有对应US州信息的实体类USState,修改方法如下:

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public List<USState> getUSStates() throws SQLException {
    List<USState> states = new ArrayList<>();
    try(
            Connection inGlobalConnections = getConnection();
            CallableStatement csmt = inGlobalConnections.prepareCall("{call mst.USP_GetUSStates()}");
            ResultSet rs = csmt.executeQuery()) { // 将ResultSet也纳入try-with-resources自动管理

        while (rs.next()) {
            USState state = new USState();
            state.setStateId(rs.getInt("StateId")); // 替换为实际字段名
            state.setStateName(rs.getString("StateName")); // 替换为实际字段名
            // 根据实际表结构添加其他字段的赋值逻辑
            states.add(state);
        }
    } catch (Exception e) {
        _log.error(e, e);
        throw e; // 重新抛出异常,让调用方感知错误
    }

    return states;
}

方案2:返回Map集合(无需新建实体类,改动极小)

如果不想创建实体类,可以用List<Map<String, Object>>来存储每行数据,适用于快速改造多个类似方法:

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public List<Map<String, Object>> getUSStates() throws SQLException {
    List<Map<String, Object>> states = new ArrayList<>();
    try(
            Connection inGlobalConnections = getConnection();
            CallableStatement csmt = inGlobalConnections.prepareCall("{call mst.USP_GetUSStates()}");
            ResultSet rs = csmt.executeQuery()) {

        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
        
        while (rs.next()) {
            Map<String, Object> rowMap = new HashMap<>();
            for (int i = 1; i <= columnCount; i++) {
                rowMap.put(metaData.getColumnName(i), rs.getObject(i));
            }
            states.add(rowMap);
        }
    } catch (Exception e) {
        _log.error(e, e);
        throw e;
    }

    return states;
}

改动说明

  • 两种方案都只需修改方法的返回类型,以及在try块内添加数据读取逻辑,其他代码结构基本不变,符合你"最小改动"的需求。
  • 所有数据库资源(Connection、CallableStatement、ResultSet)都通过try-with-resources自动关闭,无需手动管理,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:17:16