连接泄漏引发java.sql.SQLNonTransientConnectionException问题求助
核心问题分析
你的HikariCP最大连接数设为4,4次ETL迭代后连接耗尽,说明每次周期都有一个连接未被正确归还到连接池。虽然你调用了close(),但大概率是连接管理逻辑存在漏洞,导致连接无法回收到池内。
排查步骤
检查SqlDataConnector的连接生命周期逻辑
绝对不能绕过HikariCP直接从DriverManager获取连接,必须通过Spring注入的DataSource获取。同时必须保证close()在finally块中执行,避免异常分支跳过关闭操作:Connection conn = null; try { conn = dataSource.getConnection(); // 执行数据抽取操作 } catch (SQLException e) { // 异常日志记录 } finally { if (conn != null) { try { conn.close(); // HikariCP的close是归还连接到池,不是物理关闭 } catch (SQLException e) { // 记录连接关闭失败日志 } } }核查JdbcTemplate的使用规范
Spring的JdbcTemplate本身会自动管理连接的获取与归还,如果你在JdbcTemplate的回调(比如RowCallbackHandler、ResultSetExtractor)中手动打开了新连接但未关闭,就会导致泄漏。确认所有数据库操作要么完全依赖JdbcTemplate,要么手动管理的连接都有可靠的关闭逻辑。启用HikariCP泄漏检测
在配置中添加泄漏检测阈值,直接定位泄漏代码的堆栈:spring.datasource.hikari.leakDetectionThreshold=20000当连接持有超过20秒未归还时,HikariCP会在日志中打印完整的调用堆栈,直接找到泄漏点。
验证MySQL端连接限制
登录MySQL执行以下命令,确认数据库本身的最大连接数大于HikariCP的配置:show variables like 'max_connections';避免是数据库端的连接上限导致的报错。
针对性解决方案
修复SqlDataConnector的连接管理
确保所有连接都通过Spring的DataSource获取,且close()操作被包裹在finally块中,覆盖所有异常和正常分支。替换手动连接管理为JdbcTemplate
尽可能放弃手动管理连接,完全依赖JdbcTemplate、NamedParameterJdbcTemplate等Spring工具类,从根源避免连接泄漏风险。临时调整HikariCP配置(治标)
可以临时增大maximumPoolSize缓解问题,但这只是权宜之计,必须找到泄漏点才能彻底解决。你的idleTimeout和maxLifetime配置是合理的,无需调整。检查调度任务线程模型
Spring调度默认是单线程执行,如果你的ETL任务被配置为异步并发执行,可能会同时占用多个连接。确认调度任务的线程池配置,避免并发数超过连接池上限。
内容的提问来源于stack exchange,提问作者Gary Greenberg

