跳转至

8 数据库连接的首次验证validateConnection方法

8.1 简介

在DruidAbstractDataSource物理连接创建的方法createPhysicalConnection的时候说到了使用驱动包来创建连接Connection对象,当对象创建完毕之后会调用validateConnection方法来进行连接信息的验证,调用代码如下所示:

public PhysicalConnectionInfo createPhysicalConnection() throws SQLException {
            ...省略掉若干代码
            conn = createPhysicalConnection(url, physicalConnectProperties);
           ...省略掉若干代码

           //我们主要说这一行嗲吗
            validateConnection(conn);

            ....省略掉若干代码
        return new PhysicalConnectionInfo(conn, connectStartNanos, connectedNanos, initedNanos, validatedNanos, variables, globalVariables);
    }

在前面我们的Demo中我们为DruidDataSource设置了这样一个属性如下所示:

  dataSource.setValidationQuery("SELECT 1");

上面这个属性将会用到验证连接的地方。

8.2 连接的验证方法validateConnection

接下来我们来看下DruidAbstractDataSource的validateConnection方法:

 public void validateConnection(Connection conn) throws SQLException {
 //获取验证连接的SQL 这里我们配置的是SELECT 1
        String query = getValidationQuery();
        //连接关闭了 直接抛出异常结束
        if (conn.isClosed()) {
            throw new SQLException("validateConnection: connection closed");
        }
        //连接验证检查器 MySqlValidConnectionChecker
        if (validConnectionChecker != null) {
            boolean result;
            Exception error = null;
            try {
            //这个方法很重要这个方法就是连接验证的代码,原理很简单就是创建一个Statement对象然后执行一下查询语句 执行不报错则为true
                result = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);

                if (result && onFatalError) {
                    lock.lock();
                    try {
                        if (onFatalError) {
                            onFatalError = false;
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            } catch (SQLException ex) {
                throw ex;
            } catch (Exception ex) {
                result = false;
                error = ex;
            }

            if (!result) {
                SQLException sqlError = error != null ? //
                        new SQLException("validateConnection false", error) //
                        : new SQLException("validateConnection false");
                throw sqlError;
            }
            //注意这里有个return如果连接正常则直接return
            return;
        }

      //如果前面连接检查器不存在则会走这样一个默认的逻辑,,这个逻辑其实和MySqlValidConnectionChecker连接检查器里面的逻辑是一致的 验证连接的方法
        if (null != query) {
            Statement stmt = null;
            ResultSet rs = null;
            try {
                stmt = conn.createStatement();
                if (getValidationQueryTimeout() > 0) {
                    stmt.setQueryTimeout(getValidationQueryTimeout());
                }
                rs = stmt.executeQuery(query);
                if (!rs.next()) {
                    throw new SQLException("validationQuery didn't return a row");
                }

                if (onFatalError) {
                    lock.lock();
                    try {
                        if (onFatalError) {
                            onFatalError = false;
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            } finally {
                JdbcUtils.close(rs);
                JdbcUtils.close(stmt);
            }
        }
    }