validationQuery检查语句

介绍

validationQuery是Druid用来测试连接是否可用的SQL语句,这个查询语句必须是至少返回一条结果的SELECT语句。

每种数据库都有各自的验证语句,下表中从网上收集了几种常见数据库的validationQuery。

转载参考:https://www.jianshu.com/p/c9845884d735

数据库validationQuery
Oracleselect 1 from dual
MySQLselect 1
Microsoft SQL Serverselect 1
DB2select 1 from sysibm.sysdummy1
SQLiteselect 1
HSQLDBselect 1 from INFORMATION_SCHEMA.SYSTEM_USERS
postgresqlselect version()
ingresselect 1
Apache Derbyselect 1
H2select 1
Informixselect count(*) from systables

validationQuery什么时候会起作用?

当Druid遇到testWhileIdle,testOnBorrow,testOnReturn时,就会验证连接的有效性,验证规则如下:
如果有相关数据库的ValidConnectionChecker,则使用ValidConnectionChecker验证(Druid提供常用数据库的ValidConnectionChecker,包括MSSQLValidConnectionChecker,MySqlValidConnectionChecker,OracleValidConnectionChecker,PGValidConnectionChecker);

如果没有ValidConnectionChecker,则直接使用validationQuery验证;

ValidConnectionChecker是如何验证的?

MySqlValidConnectionChecker会使用Mysql独有的ping方式进行验证,其他数据库其实也都是使用validationQuery进行验证

MySqlValidConnectionChecker验证方式:

    public boolean isValidConnection(Connection conn, String validateQuery, int validationQueryTimeout) throws Exception {
        if (conn.isClosed()) {
            return false;
        }
        //Mysql使用com.mysql.jdbc.MySQLConnection的pingInternal方法进行验证
        if (usePingMethod) {
            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.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);
            }
            rs = stmt.executeQuery(query);
            return true;
        } finally {
            JdbcUtils.close(rs);
            JdbcUtils.close(stmt);
        }

    }

OracleValidConnectionChecker的验证方式:

    public boolean isValidConnection(Connection conn, String validateQuery, int validationQueryTimeout) throws Exception {
        if (validateQuery == null || validateQuery.isEmpty()) {
            validateQuery = this.defaultValidateQuery;
        }

        if (conn.isClosed()) {
            return false;
        }

        if (conn instanceof DruidPooledConnection) {
            conn = ((DruidPooledConnection) conn).getConnection();
        }

        if (conn instanceof ConnectionProxy) {
            conn = ((ConnectionProxy) conn).getRawObject();
        }

        if (validateQuery == null || validateQuery.isEmpty()) {
            return true;
        }

        int queryTimeout = validationQueryTimeout <= 0 ? timeout : validationQueryTimeout;

        Statement stmt = null;
        ResultSet rs = null;
        try {
            stmt = conn.createStatement();
            stmt.setQueryTimeout(queryTimeout);
            rs = stmt.executeQuery(validateQuery);
            return true;
        } finally {
            JdbcUtils.close(rs);
            JdbcUtils.close(stmt);
        }
    }

SqlServer的验证方式:

    public boolean isValidConnection(final Connection c, String validateQuery, int validationQueryTimeout) throws Exception {
        if (c.isClosed()) {
            return false;
        }

        Statement stmt = null;

        try {
            stmt = c.createStatement();
            if (validationQueryTimeout > 0) {
                stmt.setQueryTimeout(validationQueryTimeout);
            }
            stmt.execute(validateQuery);
            return true;
        } catch (SQLException e) {
            throw e;
        } finally {
            JdbcUtils.close(stmt);
        }
    }

结论

不同数据库的默认值不同;

如果是Mysql数据库,则validationQuery不会起作用,Mysql会使用ping的方式验证;


   转载规则


《validationQuery检查语句》 锦泉 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
责任链模式 责任链模式
之前在面试的时候被问到了,我当时刚学说不清楚,现在想起来总结一下责任链模式。
2020-12-17
下一篇 
sql注入 sql注入
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库,本文参考网上资料整理。
2020-12-15
  目录