版本: druid-1.2.5 问题: 本人项目使用druid+sqlite, 运行过程需要重启DruidDataSource, 使用的时候发现restart DruidDataSource后出现 Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 20000, active 0, maxActive 40, creating 0 重启代码为((DruidDataSource)readDataSource).restart(); 个人分析: 查看源码, restart()中调用close()
public void restart() throws SQLException { lock.lock(); try { if (activeCount > 0) { throw new SQLException("can not restart, activeCount not zero. " + activeCount); } if (LOG.isInfoEnabled()) { LOG.info("{dataSource-" + this.getID() + "} restart"); }
this.close();
this.resetStat();
this.inited = false;
this.enable = true;
this.closed = false;
} finally {
lock.unlock();
}
}
close()中将closing变量置为true, 其中closing默认初始化为false
public void close() { if (LOG.isInfoEnabled()) { LOG.info("{dataSource-" + this.getID() + "} closing ..."); }
lock.lock();
try {
if (this.closed) {
return;
}
if (!this.inited) {
return;
}
this.closing = true;
...
this.closed = true;
...
} finally {
lock.unlock();
}
...
}
在之后的init中或者其他位置, 并没有将closing重新置为false
public void init() throws SQLException { ... boolean init = false; try { ... createAndLogThread(); createAndStartCreatorThread(); # 创建启动CreateConnectionThread线程 createAndStartDestroyThread(); ... } catch (SQLException e) { ... } }
在restart()后创建的CreateConnectionThread线程中, 创建一次连接后由于closing为true会导致线程退出, 后续无法再通过empty信号量触发创建新的连接, 最终触发超时异常.
public class CreateConnectionThread extends Thread { public void run() { ... for (;;) { ...
boolean result = put(connection);
if (!result) {
JdbcUtils.close(connection.getPhysicalConnection());
LOG.info("put physical connection to pool failed.");
}
errorCount = 0; // reset errorCount
if (closing || closed) {
break;
}
}
}
}
测试通过反射在restart()后, 将closing变量改为false, 超时问题消失.
原提问者GitHub用户ribribrib2
DruidDataSource 的 restart() 方法会关闭当前数据源,并重新初始化一个新的数据源,因此会导致所有的数据库连接被关闭。在关闭连接的过程中,会涉及到关闭连接的线程,其中包括 CreateConnectionThread 线程。如果在关闭连接的过程中,CreateConnectionThread 线程正在运行,它可能会尝试使用已经关闭的连接来创建新的连接,从而抛出异常并退出线程。
为了避免这个问题,您可以在调用 restart() 方法之前,先停止所有的数据库连接。
发现1.2.6版本添加了closing=false的赋值
https://blog.51cto.com/iteyer/3237594
原回答者GitHub用户ribribrib2
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。