介绍
validationQuery是Druid用来测试连接是否可用的SQL语句,这个查询语句必须是至少返回一条结果的SELECT语句。
每种数据库都有各自的验证语句,下表中从网上收集了几种常见数据库的validationQuery。
转载参考:https://www.jianshu.com/p/c9845884d735
数据库 | validationQuery |
---|---|
Oracle | select 1 from dual |
MySQL | select 1 |
Microsoft SQL Server | select 1 |
DB2 | select 1 from sysibm.sysdummy1 |
SQLite | select 1 |
HSQLDB | select 1 from INFORMATION_SCHEMA.SYSTEM_USERS |
postgresql | select version() |
ingres | select 1 |
Apache Derby | select 1 |
H2 | select 1 |
Informix | select 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的方式验证;