Java中MySQL是如何獲得連接得?

前言

上篇文章分析了通過SPI技術如何來加載JDBC驅動連接堵泽。然后本篇繼續(xù)寫獲得連接之后的一些事。

JDBC驅動加載

image.png

上篇文章寫道恢总,當JDBC驅動被加載的時候會執(zhí)行這行代碼迎罗,將當前的Driver注冊到DriverManager中。而這段代碼的執(zhí)行主要是因為Driver的加載與初始化片仿。Driver的加載與初始化 主要是因為SPI的加載纹安。

image.png

當走到上述紅框內的代碼的時候會觸發(fā)c.newInstance,而c就是加載的Driver砂豌,因此會觸發(fā)其加載以及初始化钻蔑。好了,接著回到第一張圖奸鸯。將Driver注冊到DriverManager之后做了哪些事咪笑。點進去。

public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            // 可以看到其被封裝成了一個DriverInfo加入到了registerDrivers中娄涩,registeredDrivers是一個線程安全的list.
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

}

然后回到下面這行代碼

Connection connection = DriverManager.getConnection(url, "root", "chusen");

開始獲得數(shù)據(jù)庫連接窗怒,跟進去,最終會跟到DriverManager中比較長的getConnection方法中蓄拣,下面截取核心代碼

// 遍歷剛才存進去的Driver
for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
    if(isDriverAllowed(aDriver.driver, callerCL)) {
        try {
            // 使用Driver內的connect方法來進行獲得一個數(shù)據(jù)庫連接
            println("    trying " + aDriver.driver.getClass().getName());
            // 繼續(xù)跟到connect內部扬虚,看其做了哪些事
            Connection con = aDriver.driver.connect(url, info);
            if (con != null) {
                // Success!
                println("getConnection returning " + aDriver.driver.getClass().getName());
                return (con);
            }
        } catch (SQLException ex) {
            if (reason == null) {
                reason = ex;
            }
        }

    } else {
        println("    skipping: " + aDriver.getClass().getName());
    }
}

然后繼續(xù)向下跟進,走到了Driver的父類NonRegisteringDriver中進行連接獲得一條Connection球恤。

// 核心代碼 ---> 根據(jù)不同的類型獲得不同的連接
switch (conStr.getType()) {
    case SINGLE_CONNECTION:
        // 跟進到這里面去
        return com.mysql.cj.jdbc.ConnectionImpl.getInstance(conStr.getMainHost());

    case LOADBALANCE_CONNECTION:
        return LoadBalancedConnectionProxy.createProxyInstance((LoadbalanceConnectionUrl) conStr);

    case FAILOVER_CONNECTION:
        return FailoverConnectionProxy.createProxyInstance(conStr);

    case REPLICATION_CONNECTION:
        return ReplicationConnectionProxy.createProxyInstance((ReplicationConnectionUrl) conStr);

    default:
        return null;
}
public static JdbcConnection getInstance(HostInfo hostInfo) throws SQLException {
    // 其直接new 了一個Connection的實現(xiàn)類辜昵,跟進去看做了哪些事
    return new ConnectionImpl(hostInfo);
}

點進去可以看到大量的初始化操作,這里就不進行截圖了咽斧,仍然截取關鍵代碼堪置。

// 其中最重要的就是這一行代碼,來進行創(chuàng)建一條連接张惹。 繼續(xù)往下跟舀锨,看如何創(chuàng)建,創(chuàng)建之后做了哪些事
createNewIO(false);

unSafeQueryInterceptors();

AbandonedConnectionCleanupThread.trackConnection(this, this.getSession().getNetworkResources());

最終會跟到 connectOneTryOnly() 方法宛逗。下面為其源碼坎匿。

JdbcConnection c = getProxy();
// 進行連接MySQL服務器,拿著服務器信息,用戶名替蔬,密碼告私,還有要連接的數(shù)據(jù)庫進行連接。之后在服務器端 也可以看到連接建立了承桥。
this.session.connect(this.origHostInfo, this.user, this.password, this.database, DriverManager.getLoginTimeout() * 1000, c);

// save state from old connection
// 拿到一些連接信息德挣,這里的getAutoCommit實際上是一個默認值,為true快毛,默認為自動提交。
// 在進行事務操作時番挺,我們要將其設置為false唠帝,表示手動提交。
boolean oldAutoCommit = getAutoCommit();
// 隔離級別
int oldIsolationLevel = this.isolationLevel;
boolean oldReadOnly = isReadOnly(false);
String oldDb = getDatabase();

this.session.setQueryInterceptors(this.queryInterceptors);

// Server properties might be different from previous connection, so initialize again...
// 初始化連接信息玄柏,從服務器端進行加載的襟衰。
initializePropsFromServer();

if (isForReconnect) {
    // Restore state from old connection
    setAutoCommit(oldAutoCommit);
    setTransactionIsolation(oldIsolationLevel);
    setDatabase(oldDb);
    setReadOnly(oldReadOnly);
}

初始化連接,其實到這里就已經結束了粪摘。到后面就是使用MySQL數(shù)據(jù)庫連接了瀑晒。下面總結下具體的流程,其實流程并不是很復雜徘意。其實主要就是DriverManger.getConnectioin()這一行代碼做了哪些事苔悦。

image.png

小結

1. 其實,連接被獲取之后椎咧,可以進行緩存 做成數(shù)據(jù)庫連接池玖详。

2. SPI,未動態(tài)擴展勤讽,提供了強有力的支撐蟋座。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脚牍,隨后出現(xiàn)的幾起案子向臀,更是在濱河造成了極大的恐慌,老刑警劉巖诸狭,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件券膀,死亡現(xiàn)場離奇詭異,居然都是意外死亡驯遇,警方通過查閱死者的電腦和手機三娩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妹懒,“玉大人雀监,你說我怎么就攤上這事。” “怎么了会前?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵好乐,是天一觀的道長。 經常有香客問我瓦宜,道長蔚万,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任临庇,我火速辦了婚禮反璃,結果婚禮上,老公的妹妹穿的比我還像新娘假夺。我一直安慰自己淮蜈,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布已卷。 她就那樣靜靜地躺著梧田,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侧蘸。 梳的紋絲不亂的頭發(fā)上裁眯,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音讳癌,去河邊找鬼穿稳。 笑死,一個胖子當著我的面吹牛晌坤,可吹牛的內容都是我干的司草。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼泡仗,長吁一口氣:“原來是場噩夢啊……” “哼埋虹!你這毒婦竟也來了?” 一聲冷哼從身側響起娩怎,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤搔课,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后截亦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爬泥,經...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年崩瓤,在試婚紗的時候發(fā)現(xiàn)自己被綠了袍啡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡却桶,死狀恐怖境输,靈堂內的尸體忽然破棺而出蔗牡,到底是詐尸還是另有隱情,我是刑警寧澤嗅剖,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布辩越,位于F島的核電站,受9級特大地震影響信粮,放射性物質發(fā)生泄漏黔攒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一强缘、第九天 我趴在偏房一處隱蔽的房頂上張望督惰。 院中可真熱鬧,春花似錦旅掂、人聲如沸赏胚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至震肮,卻和暖如春称龙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背戳晌。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工鲫尊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沦偎。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓疫向,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豪嚎。 傳聞我的和親對象是個殘疾皇子搔驼,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內容