本文從 Commons DBCP testOnBorrow 的作用機制著手,管中窺豹,從一點去分析資料庫連接池獲取的程序以及架構分層設計,
以下內容會按照每層的作用,貫穿分析整個呼叫流程,
1??框架層 commons-pool
The indication of whether objects will be validated before being borrowed from the pool.
If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another.
testOnBorrow 不是 dbcp 定義的,是commons-pool 定義的,commons-pool 詳細的定義了資源池使用的一套規范和運行流程,
/**
* Borrow an object from the pool. get object from 資源池
* @see org.apache.commons.pool2.impl.GenericObjectPool#borrowObject(long)
*/
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
PooledObject<T> p = null;
// if validation fails, the instance is destroyed and the next available instance is examined.
// This continues until either a valid instance is returned or there are no more idle instances available.
while (p == null) {
// If there is one or more idle instance available in the pool,
// then an idle instance will be selected based on the value of getLifo(), activated and returned.
p = idleObjects.pollFirst();
if (p != null) {
// 設定 testOnBorrow 就會進行可用性校驗
if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
boolean validate = false;
Throwable validationThrowable = null;
try {
// 具體的校驗實作由實作類完成,
// see org.apache.commons.dbcp2.PoolableConnectionFactory
validate = factory.validateObject(p);
} catch (final Throwable t) {
PoolUtils.checkRethrow(t);
validationThrowable = t;
}
if (!validate) {
try {
// 如果校驗例外,會銷毀該資源,
// obj is not valid and should be dropped from the pool
destroy(p);
destroyedByBorrowValidationCount.incrementAndGet();
} catch (final Exception e) {
// Ignore - validation failure is more important
}
p = null;
}
}
}
}
return p.getObject();
}
2??應用層 commons-dbcp
dbcp 是特定于管理資料庫連接的資源池,
PoolableConnectionFactory is a PooledObjectFactory
PoolableConnection is a PooledObject
/**
* @see PoolableConnectionFactory#validateObject(PooledObject)
*/
@Override
public boolean validateObject(final PooledObject<PoolableConnection> p) {
try {
/**
* 檢測資源池物件的創建時間,是否超過生存時間
* 如果超過 maxConnLifetimeMillis, 不再委托資料庫連接進行校驗,直接廢棄改資源
* @see PoolableConnectionFactory#setMaxConnLifetimeMillis(long)
*/
validateLifetime(p);
// 委托資料庫連接進行自我校驗
validateConnection(p.getObject());
return true;
} catch (final Exception e) {
return false;
}
}
/**
* 資料庫連接層的校驗,具體到是否已關閉、是否與 server 連接可用
* @see Connection#isValid(int)
*/
public void validateConnection(final PoolableConnection conn) throws SQLException {
if(conn.isClosed()) {
throw new SQLException("validateConnection: connection closed");
}
conn.validate(_validationQuery, _validationQueryTimeout);
}
3??基礎層 mysql-connector-java
Returns true if the connection has not been closed and is still valid.
這個是 java.sql.Connection 定義的規范,具體實作根據對應資料庫的driver 來完成,使用某種機制用來探測連接是否可用,
/**
* 呼叫 com.mysql.jdbc.MysqlIO, 發送ping 請求,檢測是否可用
* 對比 H2 資料庫,是通過獲取當前事務級別來檢測連接是否可以,但是忽略了 timeout 配置,畢竟是 demo 資料庫 ??
*/
public synchronized boolean isValid(int timeout) throws SQLException {
if (this.isClosed()) {
return false;
} else {
try {
this.pingInternal(false, timeout * 1000);
return true;
} catch (Throwable var5) {
return false;
}
}
}
參考:MySQL 的連接時長控制--interactive_timeout和wait_timeout_翔云123456的博客-CSDN博客
總結
- commons-pool 定義資源的完整宣告周期介面,包括:makeObject、activateObject、validateObject、passivateObject、destoryObject,資源池管理物件,通過實作這些介面即可實作資源控制,參考:org.apache.commons.pool2.PooledObjectFactory
- 在校驗程序中,牽涉到很多時間,包括資源池物件的創建時間、生存時間、資料庫連接的超時時間、Mysql 連接空閑超時時間等,不同層為了服務可靠性,提供不同的時間配置,校驗也是層層遞進,最終委托到最底層來判斷,
- 校驗程序中,對于連接也會由是否已關閉的校驗(isClosed() ),包括PoolableConnection#isClosed, Connection#isClosed, Socket#isClosed, 同樣也是層層保障,確保整個架構的可靠,??
- 定義一套完整嚴謹的規范和標準,比實作一個具體的功能或者特性要求更高 ??,commons-pool 和 jdbc 定義了規范,commons-dbcp 和 mysql-connector-java 完成了具體的實作,有了規范和介面,組件和框架的對接和兼容才變為可能,
more 理解高可用
在閱讀 MySQL Driver 原始碼程序中,有個點要特別記錄下,以 MySQL Driver 創建連接為例,用重試連接實作可用性,這就是高可用,??
高可用不是一個口號,也不是復雜的概念和公式,能夠實實在在體系化的解決一類問題就是架構的目的,結合上述的架構分層,如果解決問題的方案通用性好,并且實作很優雅,就是好的架構,
// autoReconnect
public void createNewIO(boolean isForReconnect) throws SQLException {
synchronized (getConnectionMutex()) {
// jdbc.url autoReconnect 指定為 true,識別為 HighAvailability,emmm..... ??
if (!getHighAvailability()) {
connectOneTryOnly(isForReconnect, mergedProps);
return;
}
// maxReconnects 默認為 3,重試失敗的提示就是: Attempted reconnect 3 times. Giving up.
connectWithRetries(isForReconnect, mergedProps);
}
}
作者:京東物流 楊攀
來源:京東云開發者社區
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/555800.html
標籤:MySQL
上一篇:InnoDB鎖初探(一):鎖分類和RR不同場景下的鎖機制
下一篇:返回列表
