校驗時機
從 hikariPool#getConnection() 拿到的連接,如果空閑超過 500ms則要檢查它的有效性 PoolBase#isConnectionActive()
public Connection getConnection(final long hardTimeout) throws SQLException {
//... 省略其他代碼
PoolEntry poolEntry = connectionBag.borrow(timeout, MILLISECONDS);
if (poolEntry == null) {
break; // We timed out... break and throw exception
}
final long now = currentTime();
// 如果poolEntry被標記為evicted,則要關閉這個連接
// 如果poolEntry上次訪問時間到現在超過 aliveBypassWindowsMs=500ms,需要檢測下連接是否可用,如果不可用的話,關閉連接
if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > aliveBypassWindowMs
&& **!isConnectionAlive(poolEntry.connection)**)) {
closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE);
timeout = hardTimeout - elapsedMillis(startTime);
}
//... 省略其他代碼
校驗邏輯
PoolBase#isConnectionActive()
boolean isConnectionAlive(final Connection connection)
{
try {
try {
//1. 如果jdbc driver支持設置超時
setNetworkTimeout(connection, validationTimeout);
final int validationSeconds = (int) Math.max(1000L, validationTimeout) / 1000;
//2. 如果jdbc api v4支持連接的isValid()接口,就直接用這個校驗連接有效性
if (isUseJdbc4Validation) {
return connection.isValid(validationSeconds);
}
//3. 執行校驗sql判斷連接是否有效
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 {} ({}). Possibly consider using a shorter maxLifetime value.",
poolName, connection, e.getMessage());
return false;
}
就算driver不支持jdbc4的 isValid(), 需要執行sql校驗連接有效性, 校驗sql一般是 “select 1", 只會走到數據庫的 service 層,並不會走到底層存儲引擎 所以也是很快的
Hikari 校驗連接有效性的時機,就和 druid 的 testWhileIdle 一樣;
為什么不能在執行業務sql異常的時候,直接斷開異常db連接?
執行業務sql失敗的可能性很多,可能是sql語句有問題、網絡抖動、慢sql、或數據庫服務本身的問題
db連接斷開也可能是由於數據庫服務本身的一些機制或者所在機器影響導致; 連接池本身並不關心用戶到底用的哪個廠商的數據庫、哪個版本,單數據庫服務側拋出的連接關閉異常, 不同數據庫、不同版本可能都不一樣,對於通用的實現不大現實, 除非是自己公司里邊確定db版本 可枚舉的異常 定制化處理才可行