首先我想说的是,翻遍百度没有一个可用的解决方案,呵呵..我相信实际解决的人不在少数...
大家众所周知,mysql和druid可谓数据库和数据库连接池中的佼佼者...
第一次用mysql用的还是比较头疼的...
尤其是同时碰上druid...简直是要命了..
换过好几次druid版本,完全没有解决...
github上看wenshao说的,maxEvictableIdleTimeMillis用于解决mysql8小时自动中断,从源码看是有效的.
通过源码,总结一下会出现mysql8小时空闲后中断连接可能出现的情况
1.timeBetweenEvictionRunsMillis+minEvictableIdleTimeMillis>8小时
2.minIdle>0,导致druid会至少保留一个连接,使用1.0.18版本及以上版本不会存在该问题,如果你修改了mysql的wait_timeout,那么可以配置maxEvictableIdleTimeMillis判断可空闲最大时间,即使当前线程数等于minIdle也会强制回收,当然这个回收流程需要timeBetweenEvictionRunsMillis间隔时间后才会检测.
如果是其余问题,请查看druid监控页面是否有sql运行导致锁表
而我遇到的连接池挂掉正是mysql锁表导致的,有个sql锁了系统核心的那张表,所以什么操作都无法进行了
回到正题,看看druid如何执行的回收
druid回收的线程
public class DestroyTask implements Runnable {
@Override
public void run() {
shrink(true);
if (isRemoveAbandoned()) {
removeAbandoned();
}
}
}
接下来的代码也很简单易懂,超过各个参数条件设置的一律回收,有些参数api中没有提到,但是同样可以配置.
public void shrink(boolean checkTime) {
final List<DruidConnectionHolder> evictList = new ArrayList<DruidConnectionHolder>();//待回收的连接集合
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}
try {
final int checkCount = poolingCount - minIdle;//连接池连接数-最小保留连接数
final long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder connection = connections[i];
if (checkTime) {//上一个代码可以看到,传递为true
if (phyTimeoutMillis > 0) {
long phyConnectTimeMillis = currentTimeMillis - connection.getTimeMillis();//此处直接用当前时间-获取连接的时间
if (phyConnectTimeMillis > phyTimeoutMillis) {//连接不管是否空闲,存活phyTimeoutMillis后强制回收
evictList.add(connection);
continue;
}
}
long idleMillis = currentTimeMillis - connection.getLastActiveTimeMillis();//此处系统时间-该连接最后一次活跃时间,即访问数据库时间
if (idleMillis < minEvictableIdleTimeMillis) {//此处是break无问题,空闲连接从0开始排,取从最后开始取
break;
}
if (checkTime && i < checkCount) {//checkTime为true,此处验证上方的最小连接数,释放到最小连接后不再释放
evictList.add(connection);
} else if (idleMillis > maxEvictableIdleTimeMillis) {//此处验证最大存活时间,无视最小连接数强制回收
evictList.add(connection);
}
} else {
if (i < checkCount) {
evictList.add(connection);
} else {
break;
}
}
}
int removeCount = evictList.size();
if (removeCount > 0) {//此处重新复制有效连接到连接池数组中
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
poolingCount -= removeCount;
}
} finally {
lock.unlock();
}
for (DruidConnectionHolder item : evictList) {//回收连接
Connection connection = item.getConnection();
JdbcUtils.close(connection);
destroyCount.incrementAndGet();
}
}