最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java JDBC的底層實(shí)現(xiàn)原理深度解析

 更新時間:2025年11月05日 09:47:34   作者:從零開始的-CodeNinja之路  
JDBC是Java和數(shù)據(jù)庫之間的一個橋梁,是一個「規(guī)范」而不是一個實(shí)現(xiàn),能夠執(zhí)行SQL語句,JDBC由一組用Java語言編寫的類和接口組成,各種不同類型的數(shù)據(jù)庫都有相應(yīng)的實(shí)現(xiàn),這篇文章給大家介紹Java JDBC的底層實(shí)現(xiàn)原理,感興趣的朋友跟隨小編一起看看吧

一、概述

JDBC(Java DataBase Connectivity)是Java和數(shù)據(jù)庫之間的一個橋梁,是一個「規(guī)范」而不是一個實(shí)現(xiàn),能夠執(zhí)行SQL語句。JDBC由一組用Java語言編寫的類和接口組成。各種不同類型的數(shù)據(jù)庫都有相應(yīng)的實(shí)現(xiàn),注意:本文中的代碼都是針對MySQL數(shù)據(jù)庫實(shí)現(xiàn)的。

先看一個案例:

public class JdbcDemo {
    public static final String URL = "jdbc:mysql://localhost:3306/mblog";
    public static final String USER = "root";
    public static final String PASSWORD = "123456";
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1");
        while (rs.next()) {
            System.out.println("name: " + rs.getString("name") + " :年齡" + rs.getInt("age"));
        }
    }
}

二、JDBC 連接路徑

  1. 數(shù)據(jù)庫驅(qū)動:Class.forName(“com.mysql.jdbc.Driver”);
  2. 獲取鏈接:Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
  3. 創(chuàng)建Statement或者PreparedStatement對象: Statement stmt = conn.createStatement();
  4. 執(zhí)行sql數(shù)據(jù)庫查詢:ResultSet rs = stmt.executeQuery(“SELECT id, name, age FROM m_user where id =1”);
  5. 解析結(jié)果集:System.out.println(“name: “+rs.getString(“name”)+” :年齡”+rs.getInt(“age”));
  6. 最后就是各種資源的關(guān)閉。
  7. 數(shù)據(jù)庫驅(qū)動
  8. 安裝好數(shù)據(jù)庫之后,應(yīng)用程序是不能直接使用數(shù)據(jù)庫的,必須要通過相應(yīng)的數(shù)據(jù)庫驅(qū)動程序,通過驅(qū)動程序去和數(shù)據(jù)庫打交道。其實(shí)也就是數(shù)據(jù)庫廠商的JDBC接口實(shí)現(xiàn),即對Connection等接口的實(shí)現(xiàn)類的jar文件。

Driver接口:此接口是提供給數(shù)據(jù)庫廠商實(shí)現(xiàn)的。比如說MySQL的,需要依賴對應(yīng)的jar包

MySQL數(shù)據(jù)庫對應(yīng)的實(shí)現(xiàn)驅(qū)動實(shí)現(xiàn)類:

package com.mysql.cj.jdbc;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static {
        try {
            //注冊驅(qū)動
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    public Driver() throws SQLException {
    }
}

DriverManager是rt.jar包下的類,(rt=runtime),把程序需要驅(qū)動類注冊進(jìn)去。

//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){
            registeredDrivers.addIfAbsent(new DriverInfo(driver,da));
        }else{
        // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }
        println("registerDriver: "+driver);
}

類似的,可以加載其它廠商的驅(qū)動

  • Oracle驅(qū)動:Class.forName(“oracle.jdbc.driver.OracleDriver”);
  • Sql Server驅(qū)動:Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”);

獲取鏈接

看起來只有這一行代碼

Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);

深入聊聊這行代碼,到底底層是怎么連接數(shù)據(jù)庫的?

方法三個參數(shù):鏈接地址,用戶名和密碼。

public static Connection getConnection(String url,String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();
        if (user != null) {
            info.put("user", user);
        }
        if (password != null) {
            info.put("password", password);
        }
        return (getConnection(url, info, Reflection.getCallerClass()));
}

獲取連接的關(guān)鍵代碼aDriver.driver.connect(url,info); 這個方法是每個數(shù)據(jù)庫驅(qū)動自己的實(shí)現(xiàn)的。

// Worker method called by the public getConnection() methods.
private static Connection getConnection(String url,java.util.Properties info,Class caller)throws SQLException{
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        SQLException reason = null;
        //遍歷氣門注冊的數(shù)據(jù)庫驅(qū)動
        for(DriverInfo aDriver:registeredDrivers){
            try{
                //獲取連接
                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;
                }
            }
        }
}

獲取連接的關(guān)鍵代碼aDriver.driver.connect(url,info); 這個方法是每個數(shù)據(jù)庫驅(qū)動自己的實(shí)現(xiàn)的。

package com.mysql.cj.jdbc;
public class NonRegisteringDriver implements java.sql.Driver {
    @Override
    public java.sql.Connection connect(String url, Properties info) throws SQLException {
        //部分無關(guān)鍵要的代碼省略
        //...
        //下面是重點(diǎn)
        //ConnectionUrl從這個類名應(yīng)該能猜到還不到真正連接的,只是創(chuàng)建一個連接Url相關(guān)信息封裝。
        ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);
        switch (conStr.getType()) {
            //SINGLE_CONNECTION("jdbc:mysql:", HostsCardinality.SINGLE), //
            case SINGLE_CONNECTION:
                //這里就是獲取一個實(shí)例,連接就在這里面產(chǎn)生的
                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 {
        return new ConnectionImpl(hostInfo);
}

ConnectionImpl構(gòu)造方法里有調(diào)用createNewIO方法:

@Override
public void createNewIO(boolean isForReconnect){
    synchronized (getConnectionMutex()){
        try{
            if(!this.autoReconnect.getValue()){
                connectOneTryOnly(isForReconnect);
                return;
            }
            connectWithRetries(isForReconnect);
        }catch(SQLException ex){
        }
    }
}
private void connectOneTryOnly(boolean isForReconnect)throws SQLException{
        Exception connectionNotEstablishedBecause=null;
        JdbcConnection c=getProxy();
        //又看到熟悉的connet方法,
        //其中,這里的session是NativeSession
        this.session.connect(this.origHostInfo,this.user,this.password,this.database,DriverManager.getLoginTimeout()*1000,c);
        this.session.setQueryInterceptors(this.queryInterceptors);
 }
 public void connect(HostInfo hi,String user,String password,String database,int loginTimeout,TransactionEventHandler transactionManager)throws IOException{
        SocketConnection socketConnection=new NativeSocketConnection();
        //看到socket連接了,后續(xù)就是socket的連接數(shù)據(jù)庫的過程了
        socketConnection.connect(this.hostInfo.getHost(),this.hostInfo.getPort(),this.propertySet,getExceptionInterceptor(),this.log,loginTimeout);
        this.protocol.connect(user,password,database);this.protocol.getServerSession().setErrorMessageEncoding(this.protocol.getAuthenticationProvider().getEncodingForHandshake());
}
com.mysql.cj.protocol.a.NativeSocketConnection#connect
java
@Override
public void connect(String hostName, int portNumber, PropertySet propSet, ExceptionInterceptor excInterceptor, Log log, int loginTimeout) {
    this·mysqlSocket = this.socketFactory.connect(this.host, this.port, propSet, loginTimeout);
    //...
}
這里的socketFactory是StandardSocketFactory。所以也就是調(diào)用的是StandardSocketFactory的connect方法:
java
public T connect(String hostname, int portNumber, PropertySet pset, int loginTimeout) throws IOException {
    this.rawSocket = createSocket(pset);
    this.rawSocket.connect(sockAddr, getRealTimeout(connectTimeout));
}
protected Socket createSocket(PropertySet props) {
    return new Socket();
}

三、總結(jié)

數(shù)據(jù)庫驅(qū)動依賴SPI類加載機(jī)制

獲取連接是通過socket與數(shù)據(jù)庫取得連接的

到此這篇關(guān)于Java深度解剖JDBC的底層實(shí)現(xiàn)原理的文章就介紹到這了,更多相關(guān)java jdbc原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springmvc配置線程池Executor做多線程并發(fā)操作的代碼實(shí)例

    springmvc配置線程池Executor做多線程并發(fā)操作的代碼實(shí)例

    今天小編就為大家分享一篇關(guān)于springmvc配置線程池Executor做多線程并發(fā)操作的代碼實(shí)例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 一篇文章幫你搞懂什么是java的進(jìn)程和線程

    一篇文章幫你搞懂什么是java的進(jìn)程和線程

    這篇文章主要介紹了java 線程詳解及線程與進(jìn)程的區(qū)別的相關(guān)資料,網(wǎng)上關(guān)于java 線程的資料很多,對于進(jìn)程的資料很是,這里就整理下,需要的朋友可以參考下
    2021-08-08
  • 使用maven war包打包去除jar包瘦身

    使用maven war包打包去除jar包瘦身

    這篇文章主要介紹了使用maven war包打包去除jar包瘦身操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java之路徑分隔符介紹

    java之路徑分隔符介紹

    考慮到程序的可移植性,創(chuàng)建文件時建議大家選用"/",因?yàn)榻?jīng)過測試用java創(chuàng)建文件時在windows平臺下用“/”也是可以的,java貌似在后臺作過處理了。
    2013-03-03
  • 使用Java動態(tài)創(chuàng)建Flowable會簽?zāi)P偷氖纠a

    使用Java動態(tài)創(chuàng)建Flowable會簽?zāi)P偷氖纠a

    動態(tài)創(chuàng)建流程模型,尤其是會簽(Parallel Gateway)模型,是提升系統(tǒng)靈活性和響應(yīng)速度的關(guān)鍵技術(shù)之一,本文將通過Java編程語言,深入探討如何在運(yùn)行時動態(tài)地創(chuàng)建包含會簽環(huán)節(jié)的Flowable流程模型,需要的朋友可以參考下
    2024-05-05
  • Java GUI事件處理及添加對話框?qū)崿F(xiàn)方式

    Java GUI事件處理及添加對話框?qū)崿F(xiàn)方式

    文章介紹了Java中事件處理的基本概念和實(shí)現(xiàn)方法,包括事件源、事件對象、監(jiān)聽器以及不同類型的事件處理,如按鈕點(diǎn)擊、鼠標(biāo)、鍵盤和窗口事件,還提供了使用JOptionPane進(jìn)行對話框操作的示例
    2026-02-02
  • 使用shardingsphere對SQLServer坑的解決

    使用shardingsphere對SQLServer坑的解決

    本文主要介紹了使用shardingsphere對SQLServer坑的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • JDK17前后寫法超詳細(xì)對比(差點(diǎn)沒認(rèn)出是Java)

    JDK17前后寫法超詳細(xì)對比(差點(diǎn)沒認(rèn)出是Java)

    在實(shí)際應(yīng)用中,開發(fā)人員可以根據(jù)項(xiàng)目需求選擇合適的JDK版本,例如,對于需要高運(yùn)行效率和低延遲的應(yīng)用,可以選擇最新版本的JDK,以便獲得更好的性能和特性支持,這篇文章主要介紹了JDK17前后寫法超詳細(xì)對比的相關(guān)資料,需要的朋友可以參考下
    2026-04-04
  • SpringBoot Aop 詳解和多種使用場景解析

    SpringBoot Aop 詳解和多種使用場景解析

    aop面向切面編程,是編程中一個很重要的思想本篇文章主要介紹的是SpringBoot切面Aop的使用和案例,對SpringBoot Aop相關(guān)知識感興趣的朋友跟隨小編一起看看吧
    2021-08-08
  • java AOP原理以及實(shí)例用法總結(jié)

    java AOP原理以及實(shí)例用法總結(jié)

    在本篇文章里我們給大家整理了關(guān)于java AOP原理以及相關(guān)知識點(diǎn)總結(jié),正在學(xué)習(xí)的朋友們參考下。
    2019-05-05

最新評論

青阳县| 镇平县| 华容县| 紫云| 德阳市| 万年县| 雷山县| 铁力市| 西平县| 平江县| 台中市| 奉化市| 九龙县| 栖霞市| 和硕县| 四平市| 刚察县| 宜昌市| 张家港市| 威宁| 布拖县| 枣强县| 永川市| 湘潭县| 策勒县| 鹤山市| 永泰县| 昔阳县| 皮山县| 郴州市| 平远县| 资阳市| 磐安县| 玉山县| 靖安县| 兴宁市| 新乡县| 景洪市| 晋江市| 中卫市| 仁怀市|