最近测试服务器过一晚上不用 , 第二天再来就会报connection holder is null 的异常 , 然后查询可以 , 对数据库的增删改操作就不能用了 .
druid版本 1.0.9 , 这个问题 网上一搜一大堆 , 解决方案基本是要修改配置文件 .
有一种说法是在执行较长的sql时 , 如果超过了 removeAbandonedTimeout 设置的时间 , 不管是否执行完 , 都会被释放掉 .
但是我设置了一下 , 似乎没有用 .
没有办法 , 只有看源码啦 .......... ╮(╯▽╰)╭
错误日志是在这个地方打印的 ....
但是调用这个check方法的地方很多 , 初始化 , 获取连接 等地方都会先调这个方法 .
不管怎么样 , 跟着代码看吧 , 先从初始化开始 ....
我的配置文件改成酱紫了 ..... 超时设置的是30分钟 ......................
但是初始化完了之后 , 从spring看 根本就木有这个属性 ....
其他值倒是set进去了 ........
看看初始化方法走完之后 , 有值了 .....但是 不是我们设的 .....
又找了找 , 在 DruidAbstractDataSource 类中有给 removeAbandonedTimeoutMillis 属性设置默认值
protected volatile long removeAbandonedTimeoutMillis = 300 * 1000;
后面的判断也是按 removeAbandonedTimeoutMillis 来判断的 ;
是不是druid已经弃用这个removeAbandonedTimeout属性了 ?
要下班啦 , 阅兵放完假来接着跟这个问题 ......... 假期愉快
继续更~~
收回上面的推论 , 由于本地项目是工程组组 , 在另一个引用到的工程里也有数据库配置 , 所以覆盖掉了测试配置 , 删除之后 , removeAbandoned相关属性是生效的 , 那么问题来了 .....
为什么属性设置是生效的 , 依然还是会报null异常呢 ?
public int removeAbandoned() { int removeCount = 0; long currrentNanos = System.nanoTime(); ArrayList abandonedList = new ArrayList(); Map i$ = this.activeConnections; synchronized(this.activeConnections) { Iterator pooledConnection = this.activeConnections.keySet().iterator(); while(pooledConnection.hasNext()) { DruidPooledConnection buf = (DruidPooledConnection)pooledConnection.next(); if(!buf.isRunning()) { long trace = (currrentNanos - buf.getConnectedTimeNano()) / 1000000L; if(trace >= this.removeAbandonedTimeoutMillis) { pooledConnection.remove(); buf.setTraceEnable(false); abandonedList.add(buf); } } } } if(abandonedList.size() > 0) { Iterator var12 = abandonedList.iterator(); while(true) { DruidPooledConnection var13; do { if(!var12.hasNext()) { return removeCount; } var13 = (DruidPooledConnection)var12.next(); JdbcUtils.close(var13); var13.abandond(); ++this.removeAbandonedCount; ++removeCount; } while(!this.isLogAbandoned()); StringBuilder var14 = new StringBuilder(); var14.append("abandon connection, open stackTrace\n"); StackTraceElement[] var15 = var13.getConnectStackTrace(); for(int i = 0; i < var15.length; ++i) { var14.append("\tat "); var14.append(var15[i].toString()); var14.append("\n"); } LOG.error(var14.toString()); } } else { return removeCount; } }
上面这段是网上说的造成 null 异常的代码 ,
this.activeConnections
的确会取使用中的链接
如果超过
currrentNanos - buf.getConnectedTimeNano()
这个条件
就会remove掉
在这里加个断点 , 慢慢跟 .
final void afterExecute() { DruidConnectionHolder holder = this.holder; if(holder != null && holder.getDataSource().isRemoveAbandoned()) { this.running = false; holder.setLastActiveTimeMillis(System.currentTimeMillis()); } }
在每次执行完之后 , 会执行上面这个方法 .
为了测试 , removeAbandonedTimeout 设置的是10秒 , 最大连接设置的是 5 个 , 过了几分钟 , 在调接口试试 , 连接池变成这样.....
哪里不对 , 对比一下之前的连接池
明白上面问题了吧 , 下去改代码 , 晚上发一版看看明天还会不会有这问题 .