写点什么

druid 源码阅读(四)返回一个连接

  • 2022 年 5 月 13 日
  • 本文字数:1815 字

    阅读完需:约 6 分钟

在初始化连接池后就要开始返回真正的数据库连接了。

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:连接是否自动提交。

用户头像

还未添加个人签名 2021.05.30 加入

还未添加个人简介

评论

发布
暂无评论
druid 源码阅读(四)返回一个连接_五月月更_爱晒太阳的大白_InfoQ写作社区