本文主要研究下hikari鏈接池的validationTimeoutjava
默認是5秒
HikariCP/2.7.6/HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/PoolBase.java
boolean isConnectionAlive(final Connection connection) { try { try { setNetworkTimeout(connection, validationTimeout); final int validationSeconds = (int) Math.max(1000L, validationTimeout) / 1000; if (isUseJdbc4Validation) { return connection.isValid(validationSeconds); } try (Statement statement = connection.createStatement()) { if (isNetworkTimeoutSupported != TRUE) { setQueryTimeout(statement, validationSeconds); } statement.execute(config.getConnectionTestQuery()); } } finally { setNetworkTimeout(connection, networkTimeout); if (isIsolateInternalQueries && !isAutoCommit) { connection.rollback(); } } return true; } catch (Exception e) { lastConnectionFailure.set(e); LOGGER.warn("{} - Failed to validate connection {} ({})", poolName, connection, e.getMessage()); return false; } } /** * Set the network timeout, if <code>isUseNetworkTimeout</code> is <code>true</code> and the * driver supports it. * * @param connection the connection to set the network timeout on * @param timeoutMs the number of milliseconds before timeout * @throws SQLException throw if the connection.setNetworkTimeout() call throws */ private void setNetworkTimeout(final Connection connection, final long timeoutMs) throws SQLException { if (isNetworkTimeoutSupported == TRUE) { connection.setNetworkTimeout(netTimeoutExecutor, (int) timeoutMs); } } /** * Set the query timeout, if it is supported by the driver. * * @param statement a statement to set the query timeout on * @param timeoutSec the number of seconds before timeout */ private void setQueryTimeout(final Statement statement, final int timeoutSec) { if (isQueryTimeoutSupported != FALSE) { try { statement.setQueryTimeout(timeoutSec); isQueryTimeoutSupported = TRUE; } catch (Throwable e) { if (isQueryTimeoutSupported == UNINITIALIZED) { isQueryTimeoutSupported = FALSE; LOGGER.info("{} - Failed to set query timeout for statement. ({})", poolName, e.getMessage()); } } } }
若是是jdbc4的話,能夠使用isUseJdbc4Validation,是直接利用connection.isValid(validationSeconds)來驗證鏈接的有效性;不然的話則用connectionTestQuery查詢語句來查詢驗證。this.isUseJdbc4Validation = config.getConnectionTestQuery() == null;當connectionTestQuery爲null的時候,isUseJdbc4Validation爲truegit
HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.javagithub
/** * Get a connection from the pool, or timeout after the specified number of milliseconds. * * @param hardTimeout the maximum time to wait for a connection from the pool * @return a java.sql.Connection instance * @throws SQLException thrown if a timeout occurs trying to obtain a connection */ public Connection getConnection(final long hardTimeout) throws SQLException { suspendResumeLock.acquire(); final long startTime = currentTime(); try { long timeout = hardTimeout; do { PoolEntry poolEntry = connectionBag.borrow(timeout, MILLISECONDS); if (poolEntry == null) { break; // We timed out... break and throw exception } final long now = currentTime(); if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) { closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE); timeout = hardTimeout - elapsedMillis(startTime); } else { metricsTracker.recordBorrowStats(poolEntry, startTime); return poolEntry.createProxyConnection(leakTaskFactory.schedule(poolEntry), now); } } while (timeout > 0L); metricsTracker.recordBorrowTimeoutStats(startTime); throw createTimeoutException(startTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new SQLException(poolName + " - Interrupted during connection acquisition", e); } finally { suspendResumeLock.release(); } }
能夠看到borrow到poolEntry以後,若是不是isMarkedEvicted,則會調用isConnectionAlive來判斷鏈接的有效性
HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.javasql
/** * The house keeping task to retire and maintain minimum idle connections. */ private final class HouseKeeper implements Runnable { private volatile long previous = plusMillis(currentTime(), -HOUSEKEEPING_PERIOD_MS); @Override public void run() { try { // refresh timeouts in case they changed via MBean connectionTimeout = config.getConnectionTimeout(); validationTimeout = config.getValidationTimeout(); leakTaskFactory.updateLeakDetectionThreshold(config.getLeakDetectionThreshold()); final long idleTimeout = config.getIdleTimeout(); final long now = currentTime(); // Detect retrograde time, allowing +128ms as per NTP spec. if (plusMillis(now, 128) < plusMillis(previous, HOUSEKEEPING_PERIOD_MS)) { LOGGER.warn("{} - Retrograde clock change detected (housekeeper delta={}), soft-evicting connections from pool.", poolName, elapsedDisplayString(previous, now)); previous = now; softEvictConnections(); return; } else if (now > plusMillis(previous, (3 * HOUSEKEEPING_PERIOD_MS) / 2)) { // No point evicting for forward clock motion, this merely accelerates connection retirement anyway LOGGER.warn("{} - Thread starvation or clock leap detected (housekeeper delta={}).", poolName, elapsedDisplayString(previous, now)); } previous = now; String afterPrefix = "Pool "; if (idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()) { logPoolState("Before cleanup "); afterPrefix = "After cleanup "; final List<PoolEntry> notInUse = connectionBag.values(STATE_NOT_IN_USE); int toRemove = notInUse.size() - config.getMinimumIdle(); for (PoolEntry entry : notInUse) { if (toRemove > 0 && elapsedMillis(entry.lastAccessed, now) > idleTimeout && connectionBag.reserve(entry)) { closeConnection(entry, "(connection has passed idleTimeout)"); toRemove--; } } } logPoolState(afterPrefix); fillPool(); // Try to maintain minimum connections } catch (Exception e) { LOGGER.error("Unexpected exception in housekeeping task", e); } } }
HouseKeeper線程也用到了validationTimeout
validationTimeout用來指定驗證鏈接有效性的超時時間(默認是5秒,最小不能小於250毫秒
),若是是沒有設置connectionTestQuery的話,默認是用jdbc4規範中的connection.isValid(validationSeconds)來驗證鏈接的有效性。tomcat
另外hikari是在borrow鏈接的時候校驗鏈接的有效性,至關於tomcat jdbc pool的testOnBorrow=true