在我的毕设系统中,由于是动态配置的数据源,所以在测试错误的连接信息的时候,发现druid会一直重连,log无限刷新。
通过debug看到druid的重试机制,如图:
···
while(true) {
PhysicalConnectionInfo connection;
label344: {
while(true) {
try {
DruidDataSource.this.lock.lockInterruptibly();
} catch (InterruptedException var33) {
break;
}
long discardCount = DruidDataSource.this.discardCount;
boolean discardChanged = discardCount - lastDiscardCount > 0L;
lastDiscardCount = discardCount;
try {
boolean emptyWait = true;
if (DruidDataSource.this.createError != null && DruidDataSource.this.poolingCount == 0 && !discardChanged) {
emptyWait = false;
}
if (emptyWait && DruidDataSource.this.asyncInit && DruidDataSource.this.createCount < (long)DruidDataSource.this.initialSize) {
emptyWait = false;
}
if (emptyWait) {
if (DruidDataSource.this.poolingCount >= DruidDataSource.this.notEmptyWaitThreadCount && (!DruidDataSource.this.keepAlive || DruidDataSource.this.activeCount + DruidDataSource.this.poolingCount >= DruidDataSource.this.minIdle) && !DruidDataSource.this.isFailContinuous()) {
DruidDataSource.this.empty.await();
}
if (DruidDataSource.this.activeCount + DruidDataSource.this.poolingCount >= DruidDataSource.this.maxActive) {
DruidDataSource.this.empty.await();
continue;
}
}
} catch (InterruptedException var31) {
DruidDataSource.this.lastCreateError = var31;
DruidDataSource.this.lastErrorTimeMillis = System.currentTimeMillis();
if (!DruidDataSource.this.closing) {
DruidDataSource.LOG.error("create connection Thread Interrupted, url: " + DruidDataSource.this.jdbcUrl, var31);
}
break;
} finally {
DruidDataSource.this.lock.unlock();
}
connection = null;
try {
connection = DruidDataSource.this.createPhysicalConnection();
break label344;
} catch (SQLException var28) {
DruidDataSource.LOG.error("create connection SQLException, url: " + DruidDataSource.this.jdbcUrl + ", errorCode " + var28.getErrorCode() + ", state " + var28.getSQLState(), var28);
++errorCount;
if (errorCount <= DruidDataSource.this.connectionErrorRetryAttempts || DruidDataSource.this.timeBetweenConnectErrorMillis <= 0L) {
break label344;
}
DruidDataSource.this.setFailContinuous(true);
if (DruidDataSource.this.failFast) {
DruidDataSource.this.lock.lock();
try {
DruidDataSource.this.notEmpty.signalAll();
} finally {
DruidDataSource.this.lock.unlock();
}
}
if (!DruidDataSource.this.breakAfterAcquireFailure) {
try {
Thread.sleep(DruidDataSource.this.timeBetweenConnectErrorMillis);
break label344;
} catch (InterruptedException var27) {
}
}
break;
} catch (RuntimeException var29) {
DruidDataSource.LOG.error("create connection RuntimeException", var29);
DruidDataSource.this.setFailContinuous(true);
} catch (Error var30) {
DruidDataSource.LOG.error("create connection Error", var30);
DruidDataSource.this.setFailContinuous(true);
break;
}
}
return;
}
if (connection != null) {
boolean result = DruidDataSource.this.put(connection);
if (!result) {
JdbcUtils.close(connection.getPhysicalConnection());
DruidDataSource.LOG.info("put physical connection to pool failed.");
}
errorCount = 0;
}
}
···
发现druid的处理是写在一个死循环中,关键代码是:
···
DruidDataSource.LOG.error("create connection SQLException, url: " + DruidDataSource.this.jdbcUrl + ", errorCode " + var28.getErrorCode() + ", state " + var28.getSQLState(), var28);
++errorCount;
if (errorCount <= DruidDataSource.this.connectionErrorRetryAttempts || DruidDataSource.this.timeBetweenConnectErrorMillis <= 0L) {
break label344;
}
···
可以发现connectionErrorRetryAttempts和timeBetweenConnectErrorMillis都是druid配置里的参数,
connectionErrorRetryAttempts | 连接出错后再尝试连接次数 |
timeBetweenConnectErrorMillis | 关闭空闲连接的检测时间间隔 |
若希望关闭重试,可将BreakAfterAcquireFailure设置为true,connectionErrorRetryAttempts设置为0。
但是当前的请求并不会得到返回,而是一直处在等待状态,继续debug,发现问题:
在DruidDataSource.class中(第1949行),程序运行到这里就被阻塞了,而我想要获取这个异常信息。
···
try {
this.notEmpty.await();
} finally {
--this.notEmptyWaitThreadCount;
}
···
继续研究Druid的参数,发现可以设置maxWait来获取异常信息。
maxWait | 超时等待时间 |
这样的话就大可不必关闭重试了,毕竟正确的连接信息还是有重试的必要的。
通过debug可以发现,这便是我想要获得的异常信息。
···
try {
if(ChangeDataSourceHelper.changeDataSource(dbInfo)) {
List<String> lst = databaseStructureDao.databaseList();
return new Response().success(lst);
} else {
return new Response().failure("get connection failed!");
}
} catch (Exception e) {
return new Response().failure(e.getCause().getCause().getMessage());
}
···
如果您想要查看我的源码,可以访问我在github中的项目Indestrutible_backend。