mysql和oracle驅動建立連接的過程


我們知道所有的驅動程序其實都是實現相同的JDK接口來連接數據庫。這些接口其實就是JDBC接口。

那我們就從JDBC連接來看mysql驅動是怎么實現這些接口來連接數據庫的。

首先寫了一個簡單的數據庫連接程序,和mysql 建立連接

當前使用的mysql驅動是 mysql-connector-java-8.0.22.jar、jdk8.

Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=Asia/Shanghai","root","123456") ;
       Statement statement =  connection.createStatement() ;
       ResultSet resultSet = statement.executeQuery("select * from user") ;
       while (resultSet.next()){
           System.out.println((resultSet.getString("name")));
       }

 

首先我們的mysql驅動類 com.mysql.cj.jdbc.Driver通過實現 java.sql.Driver ,會在應用啟動時把驅動注冊到DriverManager當中去。這也就是說,當我們以后需要自己開發一個驅動時,也是一樣的去實現 java.sql.Driver 。

 

 

DriverManager 內部是維護了一個 list來存儲這些注冊的驅動,以供后續使用的。

// List of registered JDBC drivers
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();

 

 

 然后我們再看DriverManager怎么去getConnection的。我們可以看到getConnection里面會有一個遍歷所有的Drivers,去建立連接。

同樣的我們可以看到mysql建立連接的實現類是NonRegisteringDriver,接下來看下這里面是怎么建立連接的。

 

 

 那我們可以看到 NonRegisteringDriver 的connect方法里面就是根據不同的連接類型 建立connection實例。

這些連接類型是定義在ConnectionUrls里面的一個枚舉類  有jdbc:mysql、jdbc:mysql:loadbalance等等,就是根據我們的url來區分。

 

 

 public Connection connect(String url, Properties info) throws SQLException {
        try {
            try {
                if (!ConnectionUrl.acceptsUrl(url)) {
                    return null;
                } else {
                    ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);
                    switch(conStr.getType()) {
                    case SINGLE_CONNECTION:
                        return ConnectionImpl.getInstance(conStr.getMainHost());
                    case FAILOVER_CONNECTION:
                    case FAILOVER_DNS_SRV_CONNECTION:
                        return FailoverConnectionProxy.createProxyInstance(conStr);
                    case LOADBALANCE_CONNECTION:
                    case LOADBALANCE_DNS_SRV_CONNECTION:
                        return LoadBalancedConnectionProxy.createProxyInstance(conStr);
                    case REPLICATION_CONNECTION:
                    case REPLICATION_DNS_SRV_CONNECTION:
                        return ReplicationConnectionProxy.createProxyInstance(conStr);
                    default:
                        return null;
                    }
                }
            } catch (UnsupportedConnectionStringException var5) {
                return null;
            } catch (CJException var6) {
                throw (UnableToConnectException)ExceptionFactory.createException(UnableToConnectException.class, Messages.getString("NonRegisteringDriver.17", new Object[]{var6.toString()}), var6);
            }
        } catch (CJException var7) {
            throw SQLExceptionsMapping.translateException(var7);
        }
    }

 那我們從最簡單的 SINGLE_CONNECTION類型看 即我們url是以 jdbc:mysql開頭的。實現也是很簡單就是new ConnectionImpl 返回connection實例

 
        
case SINGLE_CONNECTION:
    return ConnectionImpl.getInstance(conStr.getMainHost());
 
        

 第二 看下常見的負載均衡連接 ,loadbalance連接時通過反射方式生成connection實例的。

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

我們可以看到LoadBalanceProxy來實現的,通過java 反射,java.lang.reflect.Proxy.newProxyInstance ,通過構造器Constructor 來生成實例對象。

真正一些策略性的選擇在 LoadBalanceProxy的構造方法中可以看到,默認是隨機策略 random

public static LoadBalancedConnection createProxyInstance(ConnectionUrl connectionUrl) throws SQLException {
    LoadBalancedConnectionProxy connProxy = new LoadBalancedConnectionProxy(connectionUrl);
    return (LoadBalancedConnection)Proxy.newProxyInstance(LoadBalancedConnection.class.getClassLoader(), INTERFACES_TO_PROXY, connProxy);
}

如下圖我們可以看到構造方法中幾種loadbalance策略選擇

RandomBalanceStrategy

BestResponseTimeBalanceStrategy

ServerAffinityStrategy

 

 第三種可以看到有主備的策略,跟loadbalance一樣通過 java 反射,java.lang.reflect.Proxy.newProxyInstance ,通過構造器Constructor 來生成實例對象。

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

 所以我們可以直接看下 ReplicationConnectionProxy 代理的實現方法。我們可以看到是優先masterConnection,

master沒有再選擇slaveConnection,this.currentConnection = this.slavesConnection;

this.currentConnection = this.initializeMasterConnection();

 

try {
            this.currentConnection = this.initializeMasterConnection();
        } catch (SQLException var10) {
            exCaught = var10;
        }

        if (this.currentConnection == null) {
            if (!this.allowMasterDownConnections || this.slavesConnection == null) {
                if (this.connectionGroup != null) {
                    this.connectionGroup.handleCloseConnection(this.thisAsReplicationConnection);
                }

                if (exCaught != null) {
                    throw exCaught;
                } else {
                    throw SQLError.createSQLException(Messages.getString("ReplicationConnectionProxy.initializationWithEmptyHostsLists"), "S1009", (ExceptionInterceptor)null);
                }
            }

            this.readOnly = true;
            this.currentConnection = this.slavesConnection;
        }

 至此我們就能生成connection實例返回,當然這只是一個很粗的鏈路,里面很多細節還是需要自己親自看看源碼是怎樣的。

當然我演示的代碼在我的github 倉庫里面有可以下載

https://github.com/xusyPersonal/springboot-mybatis-plus-demo.git  ,

這個項目是我使用springboot集成mybatis-plus的,可以簡單用來學習。今天演示的連接數據庫是這個測試類 MysqlConnectionTest,歡迎下載!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM