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

关闭Statement时MySQL随机抛出SQLException问题求助

问题分析与解决

代码场景

现有自动生成的代码如下:

Statement statement = createStatement();
try (java.sql.ResultSet resultset = statement.executeQuery()) {
    while (resultset.next()) {
        myObject.setProcessingDate(resultset.getDate(1));
        myObject.set...

    }
} finally {
    if (statement != null) {
        statement.close();
    }
}

已知Statement应当放入try-with-resources块管理,但受限于自动生成逻辑无法修改,目前会随机抛出以下异常:

异常信息

caused by: java.sql.SQLException: Streaming result set com.mysql.cj.protocol.a.result.ResultsetRowsStreaming@9h6d41205 is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. 
Ensure that you have called .close() on any active streaming result sets before attempting more queries.
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.ServerPreparedStatement.realClose(ServerPreparedStatement.java:549)
    at com.mysql.cj.jdbc.ServerPreparedStatement.close(ServerPreparedStatement.java:284)
    at com.zaxxer.hikari.pool.ProxyStatement.close(ProxyStatement.java:76)
    at mypackage.NamedParameterStatement.close(NamedParameterStatement.java:520)

问题原因

你忽略了MySQL流式结果集的特殊行为:

  • 普通结果集会一次性加载所有数据到客户端内存,此时调用Statement.close()会自动关闭关联的ResultSet;但流式结果集是逐行从服务器拉取数据,服务器端会保持结果集的活跃状态,直到客户端遍历完所有行或主动关闭ResultSet。
  • try-with-resources确实会在try块结束后自动关闭ResultSet,但如果循环过程中因异常(如网络波动、数据解析错误)提前退出,ResultSet可能未完成服务器端的资源释放流程,处于"半活跃"状态。
  • MySQL驱动在流式结果集未完全关闭时,调用Statement.close()不会自动清理ResultSet,反而会抛出该异常——这是驱动的保护机制,避免服务器端资源泄漏。
  • 异常随机出现的原因:当循环正常遍历完所有行时,ResultSet会自动完成关闭流程,此时Statement.close()可正常执行;仅当循环提前中断时,才会触发该错误。

解决办法

  1. 最优方案:修改自动生成逻辑,将Statement放入try-with-resources
    try-with-resources会按逆序自动关闭资源,先关闭ResultSet再关闭Statement,完全匹配流式结果集的要求:
    try (Statement statement = createStatement();
         ResultSet resultset = statement.executeQuery()) {
        while (resultset.next()) {
            myObject.setProcessingDate(resultset.getDate(1));
            // 其他属性设置
        }
    }
    
  2. 临时兼容方案(无法修改自动生成代码时)
    在finally块关闭Statement前,手动确保ResultSet已关闭(即使try-with-resources已处理,额外增加一次检查):
    Statement statement = createStatement();
    ResultSet resultset = null;
    try {
        resultset = statement.executeQuery();
        while (resultset.next()) {
            myObject.setProcessingDate(resultset.getDate(1));
            myObject.set...
        }
    } finally {
        if (resultset != null) {
            try {
                resultset.close();
            } catch (SQLException e) {
                // 记录日志,不影响后续流程
            }
        }
        if (statement != null) {
            statement.close();
        }
    }
    
    或者在循环中断时,主动遍历完剩余行(如果业务允许),确保服务器端结果集被正常关闭。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 02:43:25