[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 编码查看转换 | 代码下载 | 常见问题及讨论 | Python游戏编程讨论 | 《深入解析ASP核心技术》 | Python游戏编程教程 | AI图片生成
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[备忘]druid报错:connection holder is null或者connection closed

上一篇:[备忘]npm ERR! code EINTEGRITY
下一篇:[备忘]spring的getBean导致的程序卡顿

添加日期:2025/8/14 16:06:48 快速返回   返回列表 阅读658次
线上有个业务,是批量拉取数据,然后入库,每批500条,如此反复。
但是经常报错,

开始druid是低版本,报错是connection holder is null,
这个错误我以前见过,数据库杀连接会报这个错。
Caused by: java.sql.SQLException: connection holder is null
    at com.alibaba.druid.pool.DruidPooledConnection.checkStateInternal(DruidPooledConnection.java:1140)
    at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1131)
    at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:333)
--------------
升级druid到1.2.8版本后,报错变成了connection closed
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
Caused by: java.sql.SQLException: connection closed
    at com.alibaba.druid.pool.DruidPooledConnection.checkStateInternal(DruidPooledConnection.java:1190)
    at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1181)
    at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:364)
--------------
以为是数据库杀超时sql导致的,看了数据库日志,没有线索。
抓包看了,报错时也没有关TCP的情况。
然后,将注意力放到了druid的参数上。

druidDataSource.setTimeBetweenEvictionRunsMillis(60000);//毫秒
druidDataSource.setMinEvictableIdleTimeMillis(300000);
druidDataSource.setRemoveAbandoned(true);
druidDataSource.setRemoveAbandonedTimeout(1800);//秒
druidDataSource.setLogAbandoned(true);

试验了一次,大概31分钟报错,与1800秒高度吻合。
尝试改小时间,如360秒,果然差不多就报错了。
尝试druid杀连接的地方下断点,果然进入断点,证实了就是它的问题。
--------------

removeAbandoned=true
启用"连接泄露检测"功能,Druid会监控所有从连接池获取的连接
如果连接长时间未归还(达到removeAbandonedTimeout设置的值),Druid会强制回收该连接

removeAbandonedTimeout=1800(单位:秒 = 30分钟)
设置连接被认定为"泄露"的超时阈值

大概意思就是:连接最多用30分钟,就给你关了!!!

--------------
查看DruidDataSource代码,
DestroyConnectionThread里,每隔timeBetweenEvictionRunsMillis毫秒,执行destroyTask,
后者执行removeAbandoned(),

遍历每个活动连接,
long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);
if (timeMillis >= removeAbandonedTimeoutMillis) {

当前时间与获取连接时间,做差值,超过removeAbandonedTimeoutMillis毫秒数,就关闭连接,将连接标记为abandoned=true
--------------
不过,为什么后续还能获取这个连接呢?持续报错呢?为什么不从连接池清理出去呢?


在initCheck()方法中有一段代码:

         if (removeAbandoned) {
            LOG.warn("removeAbandoned is true, not use in production.");
        }
意思很明确,removeAbandoned参数并不是用在生产环境中的,是专为测试环境准备的参数。
也不知道谁加上的参数,无语
--------------
回头看业务代码,是因为开始就获取连接,然后循环批量处理,而且处理得还很慢,
当超过30分钟时就被关连接了,导致报错。
--------------
参考文档:
https://segmentfault.com/a/1190000043745778
https://www.cnblogs.com/tiancai/p/17651907.html
 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved