【JDBC4.2】二、獲取Connection

JDK版本

1.8

使用的依賴

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>6.0.5</version>
</dependency>

數據庫版本

mysql 5.5+

1 Driver接口

1.1 java.sql.Driver接口主要方法 :

//1.獲取一個Connection 
//參數info中至少包含user,password這兩個參數
//參數url中可以使用 ?key=value& 增加參數,如果key與info中重複,由JDBC的實現決定優先級
//如果給定的url不符合此驅動,則返回null
Connection connect(String url, java.util.Properties info)

//2.是否是此驅動可接受的URL
boolean acceptsURL(String url)

第三方的JDBC Driver必須實現java.sql.Driver接口,Driver實現類的靜態代碼塊static{}中應該初始化它本身,並註冊到java.sql.DriverManager中。

1.2 mysql中的實現

mysql中的Driver6.0.5的實現類 位於package com.mysql.cj.jdbc。爲:

//NonRegisteringDriver中包含所有驅動的可執行方法,但沒有包含`static{}`
public class NonRegisteringDriver implements java.sql.Driver
//包含`static{}`,會自動註冊到DriverManager
public class Driver extends NonRegisteringDriver implements java.sql.Driver

1.3 com.mysql.cj.jdbc.Driver

僅比NonRegisteringDriver 多了一個靜態代碼塊,在類加載後執行,從而自動註冊到DriverManager

static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
 }

1.4 com.mysql.cj.jdbc.NonRegisteringDriver

這個接口實現了java.sql.Driver的所有方法,測試用例如下

public class DriverTest {

    public static void main(String[] args) throws SQLException {

        String mysqlUrl="jdbc:mysql://localhost/apple";
        String otherUrl="jdbc:postgres://localhost/apple";

        Properties properties=new Properties();
        properties.put("user","pig");
        properties.put("password","123456");
        properties.put("serverTimezone","UTC");//serverTimezone是mysql-jdbc6+ 必須的參數
        properties.put("useSSL","false");//MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL attr

        java.sql.Driver driver = new com.mysql.cj.jdbc.NonRegisteringDriver();

        Connection connect = driver.connect(mysqlUrl, properties);
        System.out.println("conn : "+connect);

        boolean isAccepts1 = driver.acceptsURL(mysqlUrl);
        System.out.println("isAccepts1: "+isAccepts1);
        boolean isAccepts2 = driver.acceptsURL(otherUrl);
        System.out.println("isAccepts2: "+isAccepts2);

        DriverPropertyInfo[] propertyInfo = driver.getPropertyInfo(mysqlUrl, properties);
        System.out.println(propertyInfo.length);//mysql-driver中所有可用屬性

        System.out.println("MajorVersion:"+driver.getMajorVersion());
        System.out.println("MinorVersion:"+driver.getMinorVersion());

        //是否合乎jdbc規範-驅動需要完整地支持SQL92規範
        System.out.println("jdbcCompliant:"+driver.jdbcCompliant());

        //since JDBC 4.1, JDK 1.7
        //System.out.println("Logger:"+driver.getParentLogger());
    }
}

輸出結果如下

conn : com.mysql.cj.jdbc.ConnectionImpl@53bd815b
isAccepts1: true
isAccepts2: false
189
MajorVersion:6
MinorVersion:0
jdbcCompliant:false

2 DriverManager

從JDBC4開始(jdk1.6+),DriverManager加載時可以自動加載類路徑中的驅動,靜態代碼塊

static {
        loadInitialDrivers();//加載路徑中的驅動
        println("JDBC DriverManager initialized");
    }

加載過程如下
這裏寫圖片描述

2.1 DriverManager主要方法

//根據url,user,password獲取連接
public static Connection getConnection(String url,
        String user, String password)  
//根據url獲取驅動
public static Driver getDriver(String url)

//註冊一個驅動
public static synchronized void registerDriver(java.sql.Driver driver)

//反註冊一個驅動
public static synchronized void deregisterDriver(Driver driver)

//獲取所有驅動的Enumeration
public static java.util.Enumeration<Driver> getDrivers()

//*加載路徑下的所有驅動
private static void loadInitialDrivers()

測試用例如下:

public class ManagerTest {
    public static void main(String[] args) throws SQLException {
        String mysqlUrl = "jdbc:mysql://localhost/apple?serverTimezone=UTC&useSSL=false";

        Connection connection = DriverManager.getConnection(mysqlUrl, "pig", "123456");
        System.out.println("-------get Connection by url-----");
        System.out.println(connection);

        Driver driver = DriverManager.getDriver(mysqlUrl);
        System.out.println("-------get Driver by url-----");
        System.out.println(driver);

        Enumeration<Driver> driverEnumeration = DriverManager.getDrivers();
        System.out.println("-------All Drivers-----");
        while (driverEnumeration.hasMoreElements()) {
            System.out.println(driverEnumeration.nextElement());
        }
    }
}

輸出結果

-------get Connection by url-----
com.mysql.cj.jdbc.ConnectionImpl@48cf768c
-------get Driver by url-----
com.mysql.cj.jdbc.Driver@49476842
-------All Drivers-----
com.mysql.cj.jdbc.Driver@49476842
org.postgresql.Driver@4f023edb

2.2 loadInitialDrivers()分析

源碼如下

private static void loadInitialDrivers() {
        String drivers;
        //1.獲取環境變量中jdbc.drivers的列表
        try {
            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty("jdbc.drivers");
                }
            });
        } catch (Exception ex) {
            drivers = null;
        }

        //使用java.util.ServiceLoader#load獲取META-INFI/services/文件夾下文件中包含的類
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();
                try{
                    //依次加載所有驅動
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                    // Do nothing
                }
                return null;
            }
        });
        println("DriverManager.initialize: jdbc.drivers = " + drivers);
        if (drivers == null || drivers.equals("")) {
            return;
        }
        String[] driversList = drivers.split(":");
        println("number of Drivers:" + driversList.length);
        //依次加載環境變量中的驅動
        for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }
}

使用java.util.ServiceLoader#load獲取META-INFI/services/xxxxx文件中包含的類,xxx爲接口的全名

3 DataSource


1. javax.sql.DataSource是一個比DriverManger更好的獲取數據庫連接的方式,它通常被註冊到JNDI中。使用者通過JNDI獲取javax.sql.DataSource實例。
2. javax.sql.CommonDataSource是javax.sql.DataSource的父接口,它的子接口還包括包含連接池ConnectionPoolDataSource和分佈式事務的XADataSource。
3. javax.sql.DataSource僅用來給用戶提供了數據庫連接,沒有setUrl(),setUse()r,setPassword()等方法,需要由實現提供。

3.1 mysql中的DataSource實現


  1. com.mysql.cj.jdbc.MysqlDataSource
    作爲基本的實現,使用較多
  2. com.mysql.cj.fabric.jdbc.FabricMySQLDataSource
    可以使用 mysql Fabric功能

MySQL Fabric是什麼?
MySQL Fabric能“組織”多個MySQL數據庫,是應用系統將大於幾TB的表分散到多個數據庫,即數據分片(Data Shard)。在同一個分片內又可以含有多個>數據庫,並且由Fabric自動挑選一個適合的作爲主數據庫,其他的數據庫配置成從數據庫,來做主從複製。在主數據庫掛掉時,從各個從數據庫中挑選一個提>升爲主數據庫。

com.mysql.cj.jdbc.MysqlDataSource

示例代碼:

com.mysql.cj.jdbc.MysqlDataSource dataSource=new com.mysql.cj.jdbc.MysqlDataSource();
dataSource.setUrl("jdbc:mysql://localhost/apple?serverTimezone=UTC&useSSL=false");
dataSource.setUser("pig");
dataSource.setPassword("123456");
System.out.println(dataSource.getConnection());
System.out.println(dataSource.getDatabaseName());
//.....其他方法

3.2 SpringJDBC中的DataSource實現

詳見我的另一篇博客 《SpringJDBC中的DataSource的實現》

4 Connection接口

Connection表示於數據庫的一個連接。
Connection可以通過Driver,DriverManager,DataSource獲取,也可以直接使用new來生成。
下圖是mysql-connector-java6.05的部分實現
這裏寫圖片描述

ConnectionImpl是一個基本的Connection實現。
LoadBalancedMySQLConnection具有負載均衡的功能。

com.mysql.cj.jdbc.ConnectionImpl有一個構造器ConnectionImpl(HostInfo hostInfo) 是public的。

發佈了111 篇原創文章 · 獲贊 158 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章