在初始化连接池后就要开始返回真正的数据库连接了。
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:连接是否自动提交。
评论