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

SpringBoot+Azure SQL Server查询10万条记录报Connection reset问题

问题分析与解决指南

首先从异常栈可以明确:你配置queryTimeout解决不了问题,因为故障根本不在数据库查询环节。
异常抛出点在Jackson序列化响应、往客户端写数据的阶段(栈里明确能看到UTF8JsonGenerator._flushBuffer、OutputBuffer.realWriteBytes的调用链),抛出的ClientAbortException: Connection reset by peer本质是连接被对端主动断开,和SQL执行超时没有关系。

先修正代码里的明显用法错误

你当前JdbcTemplate的RowCallbackHandler实现是错的:
RowCallbackHandler的设计逻辑是JdbcTemplate遍历结果集时,每读到一行就回调一次processRow方法,不需要你手动写while (resultSet.next())做循环。你现在的写法会在第一次触发回调时就把整个结果集全部遍历完,后续回调拿到的ResultSet已经是遍历结束的状态,虽然当前精简代码逻辑碰巧能跑,但不符合组件设计预期,还会放大内存占用问题。
正确的写法如下:

List<TableName> tnames = new ArrayList<>();
jdbcTemplate.query("select * from testdb.table_name", (RowCallbackHandler) resultSet -> {
    // 不要加while循环,框架已经处理了逐行遍历逻辑
    TableName tn = new TableName();
    tn.setStatus(resultSet.getString("status"));
    tnames.add(tn);
    // 单行处理逻辑
});
return tnames;

如果需要手动控制结果集遍历逻辑,应该改用ResultSetExtractor,不要在RowCallbackHandler里自己循环ResultSet。

核心故障原因排查方向

你测试到返回行数超过47000就报错,本质是行数达到阈值后,整个请求的全链路耗时/资源占用超过了临界值,按优先级排查以下点:

  • 链路超时被截断
    你测的SQL在数据库端执行就要12-17秒,这还没算JDBC驱动跨网络从Azure SQL拉取数据到应用、应用把全量数据加载到内存、序列化成JSON的时间,总耗时很容易超过前置链路的超时阈值:
    • 如果服务前面挂了Azure应用网关、API管理、Front Door这类七层代理,默认请求超时通常是30秒,部分自定义配置可能更短
    • 调用方(前端、下游服务)本身设置的请求超时如果小于接口总耗时,会主动断开连接,直接抛出你看到的连接重置错误
    • 47000行刚好是总耗时触达超时阈值的临界点,行数更少的时候总耗时没超就能正常返回
  • 内存占用导致的停顿
    几万行数据全量加载到JVM堆内存存成List,再一次性序列化成大JSON串,会生成大对象占用堆内存:
    • 如果JVM堆配置不足,会触发长时间Full GC,导致应用暂停无法往连接写数据,对端会判定连接失效主动断开
    • Tomcat默认响应缓冲区只有8KB,大响应需要多次刷出缓冲区,如果GC停顿时间过长,同样会触发连接断开
  • JDBC驱动拉取模式不合理
    SQL Server的JDBC驱动默认会一次性把全量结果集拉到应用侧内存,不是逐行流式读取,你感知到的12-17秒耗时里,有很大一部分是跨网从Azure拉数据的时间,进一步拉长了整体请求耗时。

可落地的解决方案

按改造成本从低到高选择:

快速修复方案

  1. 先修正前面提到的RowCallbackHandler用法错误,避免结果集处理逻辑异常
  2. 统一调整全链路超时配置:把七层网关、负载均衡、调用端的请求超时阈值调到60秒以上,长查询接口建议走异步Servlet处理,避免占用容器工作线程
  3. 给JDBC连接串加参数selectMethod=cursor,启用游标模式流式读取结果集,不要一次性把全量数据加载到应用内存,降低内存占用和数据拉取等待时间
  4. 适当调大服务的JVM堆内存,避免大结果集触发频繁Full GC

长期最优方案

  1. 普通业务接口禁止一次性返回10万行数据,改成分页查询,单次返回1000-5000行,是稳定性最高的方案
  2. 如果是全量数据导出场景,不要走普通JSON同步接口:改成异步任务模式,接口接收到请求后立即返回任务ID,后台异步跑查询生成CSV/Excel文件存到对象存储,用户凭任务ID下载文件,完全避开长连接超时问题
  3. 必须同步返回大结果集的场景,用Jackson流式序列化API,边读数据库边往响应输出流写JSON,不需要把全量数据存在List里占内存,同时能第一时间返回响应头,避免连接被判定为空闲断开。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:45:32