在初始化连接池后就要开始返回真正的数据库连接了。
1、getConnectionInternal
通过一个循环从连接池里返回物理连接,如果该方法抛出 GetConnectionTimeoutException 错误,只要连接没有满(this.poolingCount + this.activeCount < this.maxActive)且小于设置的失败重试次数,就一直重试。
try {
poolableConnection = getConnectionInternal(maxWaitMillis);
} catch (GetConnectionTimeoutException ex) {
if (notFullTimeoutRetryCnt <= this.notFullTimeoutRetryCount && !isFull()) {
notFullTimeoutRetryCnt++;
if (LOG.isWarnEnabled()) {
LOG.warn("get connection timeout retry : " + notFullTimeoutRetryCnt);
}
continue;
}
throw ex;
}
复制代码
2、testOnBorrow
如果该变量配置为 true 的话,会调用 testConnectionInternal(poolableConnection.holder, poolableConnection.conn)方法对连接进行有效性验证。主要是使用连接池初始化时确定的 validConnectionChecker 中的 isValidConnection 方法对连接进行检验。
//连接是否已经关闭
if (conn.isClosed()) {
return false;
}
if (usePingMethod) {
//启用ping方法
if (conn instanceof DruidPooledConnection) {
conn = ((DruidPooledConnection) conn).getConnection();
}
if (conn instanceof ConnectionProxy) {
conn = ((ConnectionProxy) conn).getRawObject();
}
if (clazz.isAssignableFrom(conn.getClass())) {
if (validationQueryTimeout <= 0) {
validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT;
}
try {
//判读是否可以ping通
ping.invoke(conn, true, validationQueryTimeout * 1000);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof SQLException) {
throw (SQLException) cause;
}
throw e;
}
return true;
}
}
String query = validateQuery;
if (validateQuery == null || validateQuery.isEmpty()) {
query = DEFAULT_VALIDATION_QUERY;
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
if (validationQueryTimeout > 0) {
stmt.setQueryTimeout(validationQueryTimeout);
}
//通过执行validateQuery判断连接是否可用
rs = stmt.executeQuery(query);
return true;
} finally {
JdbcUtils.close(rs);
JdbcUtils.close(stmt);
}
}
复制代码
如果校验没有通过,就丢弃这个连接。
testOnBorrow 如果配置为 false,
if (testWhileIdle) {
...
if (idleMillis >= timeBetweenEvictionRunsMillis
|| idleMillis < 0 // unexcepted branch
) {
//空闲时间大于连接检测探活时间,测试一下连接可用性
boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
if (!validate) {
if (LOG.isDebugEnabled()) {
LOG.debug("skip not validate connection.");
}
discardConnection(poolableConnection.holder);
continue;
}
}
复制代码
3、removeAbandoned
开启该参数后,会把当前线程的 stackTrace 设置到返回的连接中,然后把当前连接放入 activeConnections 中。该参数的主要作用是在程序获取连接后如果长时没有释放连接,就强制回收连接,防止连接泄露,现在使用 ORM 框架一般不会有这个问题。
4、总结
经过一系列检查后,最后返回了封装后的 DruidPooledConnection 连接。这其中主要用到了这几个参数:
testOnBorrow:开启后会在获取连接的时候就检查连接的可用性,因为每次获取连接都检查连接可用性,所以配置该参数会影响性能。
testWhileIdle:开启后在申请连接时,连接空闲时间大于 timeBetweenEvictionRunsMillis 时,会检查连接的可用性,默认 1 分钟。
removeAbandoned:开启后在程序获取连接后如果长时没有释放连接,就强制回收连接,防止连接泄露。
defaultAutoCommit:连接是否自动提交。
评论