Spring JdbcTemplate调用queryForMap时Tomcat连接池报连接未关闭问题咨询
可能的原因及边界场景
正常情况下Spring JdbcTemplate的所有查询方法都会在finally代码块中主动释放连接,不存在原生连接泄露问题,你遇到的报错大概率是以下几种场景导致的:
- 事务上下文持有连接,报错栈仅为回收时的执行点
如果getMaxSize方法的调用链路处于Spring事务上下文中,JdbcTemplate会复用当前事务绑定的连接,不会主动关闭连接,连接需要等事务提交/回滚后才会被释放回连接池。如果事务整体执行耗时超过你配置的removeAbandonedTimeout=120,就会被连接池标记为遗弃连接,此时的报错栈只会记录连接被回收时正在执行的方法,也就是getMaxSize,它只是背锅方,真正的问题是上游事务耗时过长。 - ResetAbandonedTimer拦截器导致的误定位
你配置的ResetAbandonedTimer拦截器会在每次数据库操作时重置连接的遗弃超时计时器,如果你有其他长耗时操作持有了连接,中间调用getMaxSize时重置了计时器,最后连接超时时的调用栈就会指向这个方法,无法匹配到真正的连接持有者。 - 版本兼容问题
排查你当前使用的Spring版本、MariaDB驱动版本、Tomcat连接池版本是否存在已知bug:- 部分低版本Spring的JdbcTemplate在处理特殊返回值/空结果集时存在资源释放遗漏
- 部分旧版本MariaDB驱动关闭连接的标记无法正确同步给Tomcat连接池,导致连接池误以为连接仍被占用
- Utils类实例化方式异常
如果你的Utils类不是被Spring容器托管,而是手动通过new关键字实例化,即使字段加了@Autowired也不会被自动注入,如果你是通过其他方式手动给jdbcTemplate字段赋值,不排除赋值的JdbcTemplate实例本身配置错误,没有绑定正确的DataSource和资源释放逻辑。
排查建议
- 打印
getMaxSize方法执行时的事务状态:调用TransactionSynchronizationManager.isActualTransactionActive(),如果返回true,直接向上排查上游事务的执行耗时和事务逻辑是否存在异常。 - 临时把
removeAbandonedTimeout调整到300秒,如果报错消失,可以确认是长耗时操作持有连接超过阈值导致,而非JdbcTemplate本身的连接释放问题。 - 完整打印遗弃连接的栈信息,找到最上层开启连接/开启事务的调用点,不要只关注报错栈里的
getMaxSize方法。
你当前的queryForMap用法以及返回值引用逻辑不会持有任何连接相关资源,不可能直接导致连接一直处于开启状态。
内容的提问来源于stack exchange,提问作者Galen
相关产品推荐
相关产品推荐

