對比5.1.48VS8.0.16版本 getConnection、isValid
一、驅動以及目錄結構
官網地址:https://dev.mysql.com/doc/relnotes/connector-j/8.0/en/
1.1 驅動對比
5.1.48 引入驅動時名稱爲:com.mysql.jdbc.Driver
8.0.16 引入驅動時名稱爲:com.mysql.cj.jdbc.Driver ,如果 驅動還配置 5.x 的版本,也沒有問題,只是會如下提示:
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
但是還是會自動 切換成 新的驅動,原因如下,主要是做了代碼兼容,讓原先的Driver繼承了com.mysql.cj.jdbc.Driver ,然後在
然後com.mysql.cj.jdbc.driver 裏面的 靜態塊 進行註冊:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
在DriverManager 類裏面的 通過了SPI 進行了註冊和初始化:
/**
* Load the initial JDBC drivers by checking the System property
* jdbc.properties and then use the {@code ServiceLoader} mechanism
*/
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
1.2 目錄結構對比
5.1.X的源碼目錄結構和 8.0.16 的代碼結構也有很大的變化,這裏就不貼圖了,感興趣的自己去下載源碼看,源碼地址:gitHub地址
這裏對比一下 對JDK 的要求:
此外,JDBC 版本和 JDK 對應的關係如下:
一、JDBC 1.0 隨JDK1.1發佈;
二、JDBC 2.0 隨JDK1.2 和 JDK1.3 發佈
JDBC 2.0 和 JDBC 2.1 API 被分入兩個包:
java.sql 包(包括核心 API;它是 JDBC 1.22 API 的增強)
javax.sql 包(可選的包,用於支持連接池、分佈式事務及其他類似的高級功能)。
三、JDBC3.0 隨JDK1.4發佈
四、JDBC 4.0 隨 JDK1.6 發佈
五、JDBC4.1 隨 JDK1.7 發佈
六、JDBC4.2 隨 JDK1.8 發佈
二 getConnection流程對比
這裏主要是分析的正常流程:
2.1 5.1.48版本getConnection
大致流程:
- 判斷url 是否爲空,爲空澤拋出異常
- 判斷url 是否以"jdbc:mysql:loadbalance://" 開頭,是則創建對應的負載均衡的connet,否則繼續步驟3
- 判斷url是否以“jdbc:mysql:replication://” 開頭,是澤創建對應的Replication
的connect,否則繼續 - 對URL 進行 解析,轉換成Properties 以便後面使用
- 判斷NUM_HOSTS 是否 >1 ,是 則 走connectFailover 流程,否則繼續
- 判斷是否是 jdbc4, 是支持jdbc4的,那就先 通過構造函數實例JDBC4Connection
- JDBC4Connection 繼承了 ConnectionImpl,這裏 會 createNewIO(false); 進行和mysql server進行創建connection
- 通過StandardSocketFactory 創建 socketFactory,使用標準的 TCP/IP sockets (the
standard) 進行socket 連接 - 通過BufferedOutputStream 進行 確定,這樣一個connection就創建完成.
2.2、8.0.16版本的getConnection流程
大致流程如下:
- 判斷url 是否爲空,如果爲空,拋出異常
- 通過正則表達式驗證 URL的開頭是否符合規定的,這裏 通過枚舉列出來,5.1.48 是逐個判斷,個人感覺8.0.X的 代碼結構相關整潔一些,類型如下,官方給出解釋,不同的數據庫用錯驅動比較常見,比如用的ServerSQL 的數據庫,用的mysql 的驅動
- 對URL 進行拼接,拼接玩,用此鏈接作爲Key,從緩存裏面獲取對應的ConnectionUrl 實例
private static final LRUCache<String, ConnectionUrl> connectionUrlCache = new LRUCache<>(100);
4. 獲取到了就直接返回,獲取不到就 通過 Class.forName 進行構造
5. 拿到ConnectionUrl 之後,根據對應的Type 進行和 mysql Server 創建Connection
6. 先對各類參數進行初始化,然後 createNewIO(false);
7. 這裏通過 TCP/IP sockets (the standard) 開始進行連接, 建立之後 ,連接的狀態是
:unauthenticated user,還沒去確認,等待client 端確認.
8. 這裏相對 5.1.48 做了進一步的細化, 創建了一個 protocol , 明確了:物理連接僅負責 I / O流,而 protocol 負責創建 session ,以及 內部認證,protocol 對 讀取和發送消息也進行了封裝.,這裏 protocol.connect 進行確認,正式創建連接
三、isValid 流程對比
兩個版本的isValid ,都是拿到連接之後,通過socket 發送一個 a ping command給到 mysql Server ,然後讀取對應的消息,如果獲取到的是 java.io.EOFException ,說明此connection 已經斷開,拋出異常, 兩個版本的大致流程基本一樣,這裏就不貼對比了,直接貼一下兩個的大致流程路徑:
四、對比總結
4.1 getConnection 小結
-
8.0.16 對整個代碼的結構進行了調整, 原先 5.1.x 很多的if …else 這類分支 ,8.0.16版本 通過正則 匹配 過濾掉不符合 規範的url ,再 通過 枚舉 方式 匹配對應的 情況,這樣代碼更加簡潔, 也更加直接,不符合的url 直接返回而不需要到創建的時候才發現不符合,效率更高.
-
8.0.16 裏面設置了一個 緩存,key 爲拼接好的URL ,value 對對應的connectionUrl, 創建連接時,每次的url一樣就不用每次都通過構造函數來進行創建 ,這裏進行了一定的優化,創建的速度更快
-
在 和mysql server 進行創建 連接時,都是創建socket 連接,但8.0.16 把很多的代碼進行了重新整合,引入了一個 protocol 輔助類,對一些讀寫 方法 都重新封裝,層次更加清晰了一些,也對校驗進行了一定程度的增強.
4.2 其他對比
-
8.0.16 依賴 JDBC 4.2 ,所以要求JDK1.8
-
8.0.16 版本修復了一些bug 和對一些方法進行了整合,詳見:mysql-connector-java 官方描述