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

Java执行SELECT查询时遇ResultSet is from UPDATE异常(高负载场景)

问题描述

在Java中调用executeQuery方法执行SELECT查询时,明明执行的是SELECT语句,却抛出SQLException,错误提示为:

ResultSet is from UPDATE. No Data.

该问题仅在高负载场景下出现,低负载时查询可正常运行。当前使用mysql connector 8.0.16,目前只能通过重启服务器临时解决,需要在代码层面处理以保障系统稳定性。

示例函数代码如下:

public CacheKey getResult(String type, String colId) {
    ResultSet resultSet = null;
    PreparedStatement statement = null;
    CacheKey returnEntry = null; // 补充原代码遗漏的变量声明
    try {
        
        String request = "select * from Table where a = ?";
        // mCxnContainer是类级别声明的连接对象
        statement = mCxnContainer.getStatement(request);
        if (statement == null) {
             mCxnContainer = getNewConnection();
             statement = mCxnContainer.getStatement(request);
        }
        statement.setString(1, colId);
        resultSet = statement.executeQuery();
        returnEntry = cacheEntry.toEntry(resultSet);
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            if (resultSet != null)
                resultSet.close();
            if (statement != null)
                statement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return returnEntry;
}
问题原因与解决方案

核心原因

这个问题大概率是连接池/共享连接被污染导致的:高负载下,同一个数据库连接被复用,之前的UPDATE/INSERT/DELETE操作未正确清理资源,导致后续SELECT请求复用连接时,驱动认为当前结果集来自更新操作而非查询。另外mysql connector 8.0.16存在部分连接复用相关的bug,也可能触发该问题。

代码层面修复方案

1. 避免类级别共享连接,改用方法内独立管理

原代码中mCxnContainer是类级别共享的连接对象,高负载下多线程并发会导致连接被交叉使用,直接引发资源污染。应改为每次请求获取独立连接,用完即释放:

public CacheKey getResult(String type, String colId) {
    ResultSet resultSet = null;
    PreparedStatement statement = null;
    CacheKey returnEntry = null;
    Connection conn = null; // 方法内独立管理连接
    try {
        String request = "select * from Table where a = ?";
        // 每次请求获取新连接或从连接池取独占连接
        conn = getNewConnection();
        statement = conn.prepareStatement(request);
        statement.setString(1, colId);
        resultSet = statement.executeQuery();
        returnEntry = cacheEntry.toEntry(resultSet);
    } catch (SQLException e) {
        e.printStackTrace();
        // 异常时判断是否为连接问题,尝试重试
        if (isConnectionError(e)) {
            return retryQuery(type, colId);
        }
    } finally {
        // 按顺序关闭资源:ResultSet → Statement → Connection
        try {
            if (resultSet != null) resultSet.close();
            if (statement != null) statement.close();
            if (conn != null) conn.close(); // 必须关闭连接归还到池
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return returnEntry;
}

// 判断是否为连接相关异常的辅助方法
private boolean isConnectionError(SQLException e) {
    String msg = e.getMessage();
    return msg != null && (msg.contains("ResultSet is from UPDATE") 
            || msg.contains("Connection closed") 
            || msg.contains("Lost connection"));
}

// 重试逻辑(限制次数避免死循环)
private CacheKey retryQuery(String type, String colId) {
    int retryTimes = 2;
    while (retryTimes-- > 0) {
        try {
            return getResult(type, colId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return null;
}

2. 升级mysql connector版本

8.0.16版本存在已知的连接复用bug,建议升级到8.0.28及以上稳定版本,官方已修复部分高负载下的连接状态异常问题。

3. 获取连接时强制校验有效性

如果必须使用连接池,在获取连接时强制校验连接状态,避免使用已污染的连接:

// 获取连接时添加有效性检查
public Connection getNewConnection() throws SQLException {
    Connection conn = yourConnectionPool.getConnection();
    // 执行简单查询校验连接是否正常
    try (Statement stmt = conn.createStatement()) {
        stmt.executeQuery("SELECT 1");
    } catch (SQLException e) {
        conn.close();
        return yourConnectionPool.getConnection(); // 重新获取可用连接
    }
    return conn;
}

4. 不要自定义缓存PreparedStatement

原代码中mCxnContainer.getStatement(request)可能是自定义缓存了PreparedStatement,高负载下多线程共用会导致参数交叉覆盖、结果集污染,应改为每次请求创建新的PreparedStatement,或使用连接池自带的PreparedStatement缓存机制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:46:01