这个版本连接池默认增加配置connectTimeout和socketTimeout,增强了SQL Parser
在源码com.alibaba.druid.pool.DruidAbstractDataSource#createPhysicalConnection()方法中新增了如下代码:
if (connectTimeout > 0) {
if (isMySql) {
physicalConnectProperties.put("connectTimeout", connectTimeout);
} else if (isOracle) {
physicalConnectProperties.put("oracle.net.CONNECT_TIMEOUT", connectTimeout);
} else if (driver != null && "org.postgresql.Driver".equals(driver.getClass().getName())) {
physicalConnectProperties.put("loginTimeout", connectTimeout);
physicalConnectProperties.put("socketTimeout", connectTimeout);
}
}
对mysql、oracle、postgresql数据库驱动配置连接超时时间,在连接的时候生效,默认值:10000ms
在数据库出现宕机或网络宜昌市,jdbc的socket超时是必须的,由于TCP/IP结构,socket没有办法检测到网络错误,因此应用程序也不能检测到与数据库之间的连接是否已经断开。如果没有socket超时,应用程序会一直等待数据库返回结果。为了避免死连接,socket必须设置超时时间,通过设置超时时间,可以防止出现网络错误时一直等待的情况并缩短故障时间。
在源码com.alibaba.druid.pool.DruidAbstractDataSource#createPhysicalConnection()中新增如下代码:
if (socketTimeout > 0 && !netTimeoutError) {
try {
//默认sql执行10s
conn.setNetworkTimeout(netTimeoutExecutor, socketTimeout);
} catch (SQLFeatureNotSupportedException | AbstractMethodError e) {
netTimeoutError = true;
} catch (Exception ignored) {
// ignored
}
}
其中netTimeoutExecutor是SynchronousExecutor的实例对象
class SynchronousExecutor implements Executor {
@Override
public void execute(Runnable command) {
try {
command.run();
} catch (AbstractMethodError error) {
netTimeoutError = true;
} catch (Exception ignored) {
if (LOG.isDebugEnabled()) {
LOG.debug("failed to execute command " + command);
}
}
}
}
SynchronousExecutor是在com.alibaba.druid.pool.DruidDataSource#init方法中进行初始化
其中command的具体实现是com.mysql.cj.jdbc.ConnectionImpl.NetworkTimeoutSetter(mysql的具体实现)
private static class NetworkTimeoutSetter implements Runnable {
private final WeakReference<JdbcConnection> connRef;
private final int milliseconds;
public NetworkTimeoutSetter(JdbcConnection conn, int milliseconds) {
this.connRef = new WeakReference(conn);
this.milliseconds = milliseconds;
}
public void run() {
JdbcConnection conn = (JdbcConnection)this.connRef.get();
if (conn != null) {
synchronized(conn.getConnectionMutex()) {
((NativeSession)conn.getSession()).setSocketTimeout(this.milliseconds);
}
}
}
}
具体实现代码在com.alibaba.druid.pool.DruidAbstractDataSource#initStatement中如下:
void initStatement(DruidPooledConnection conn, Statement stmt) throws SQLException {
boolean transaction = !conn.getConnectionHolder().underlyingAutoCommit;
int queryTimeout = transaction ? getTransactionQueryTimeout() : getQueryTimeout();
if (queryTimeout > 0) {
stmt.setQueryTimeout(queryTimeout);
}
}
public int getTransactionQueryTimeout() {
if (transactionQueryTimeout <= 0) {
return queryTimeout;
}
return transactionQueryTimeout;
}
public int getQueryTimeout() {
return queryTimeout;
}
看了上面的几个时间设置估计会有点懵逼,这么多时间怎么区分,先看一下从网上找到的图:

高级别的timeout依赖于低级别的timeout,只有当低级别的timeout无误时,高级别的timeout才能确保正常;如:当socket timeout出问题时,高级别statement timeout和transaction timeout都将失效。statement timeout无法处理网络连接失败时的超时,它能做的仅仅是限制statement的操作时间,网络连接失败时的timeout必须交由JDBC来处理,JDBC的socket timeout会受到操作系统socket timeout设置的影响。