JDBC驅動程序註冊 JDBC簡介(二)

使用JDBC進行數據庫操做的第一步就是驅動註冊(固然你得先導入JAR)。
驅動註冊有多種方式,第一步必然是得到正確的驅動名稱與URL格式

驅動名稱與URL格式

RDBMS 驅動程序名稱       
URL格式
MySQL com.mysql.jdbc.Driver       
jdbc:mysql://hostname/databaseName
ORACLE oracle.jdbc.driver.OracleDriver       
jdbc:oracle:thin:@hostname:portNumber:databaseName
PostgreSQL org.postgresql.Driver jdbc:postgresql://hostname:port/dbname
DB2 com.ibm.db2.jdbc.net.DB2Driver jdbc:db2:hostname:port Number/databaseName
Sybase com.sybase.jdbc.SybDriver jdbc:sybase:Tds:hostname: portNumber/databaseName
 
經常使用的驅動程序名稱與URL格式如上表所示隨着版本變化,會存在些許變更,若有不對,還需從新查驗
好比MYSQL中5與6 , mysql5用的驅動是com.mysql.jdbc.Driver,mysql6之後用的是com.mysql.cj.jdbc.Driver

MYSQL的驅動下載

MYSQL的connector下載地址
https://dev.mysql.com/downloads/connector/
image_5c3d32d7_5605
另外還有完整的文檔

oracle驅動下載

https://www.oracle.com/technetwork/database/application-development/jdbc/downloads/index.html
image_5c3d32d7_74d8

驅動註冊

在經過驅動管理器建立鏈接前須要進行驅動註冊
驅動註冊有三種形式
    Class.forName("com.mysql.jdbc.Driver");
    DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver");
 
能夠查看mysql-connector中的源碼
package com.mysql.jdbc; import java.sql.SQLException; 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!"); } } /** * Construct a new driver and register it with DriverManager * * @throws SQLException * if a database error occurs. */

public Driver() throws SQLException { // Required for Class.forName().newInstance()
 } }

 

類加載時,會執行<clinit>方法,在jvm第一次加載class文件時調用,包括靜態變量初始化語句和靜態塊的執行 。
因此Class.forName("com.mysql.jdbc.Driver");會調用java.sql.DriverManager.registerDriver(new Driver());  完成了驅動的註冊
因此直接調用java.sql.DriverManager.registerDriver(new Driver()); 也是能夠的
 
驅動管理器類加載時,也會從系統屬性"jdbc.drivers" 中獲取數據
因此,在驅動管理器加載以前,可使用    System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver"); 進行設置
也能夠同時設置多個好比System.setProperty("jdbc.drivers","XXXDriver:XXXDriver:XXXDriver");
image_5c3d32d7_5ea7
 
  • DriverManager.registerDriver(new com.mysql.jdbc.Driver());  依賴具體,沒有面向抽象編程,不推薦
  • System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver"); DriverManager加載前有用,不夠靈活方便
  • Class.forName("com.mysql.jdbc.Driver"); 一般使用

自動加載的4.0時代

從JDBC4.0開始,就不在須要主動的顯式加載,對應JDK6
在調用 getConnection 方法時,DriverManager 會試着從初始化時加載的那些驅動程序以及使用與當前 applet 或應用程序相同的類加載器顯式加載的那些驅動程序中查找合適的驅動程序。
 
image_5c3d32d7_2d14
JDBC 4.0 的規範規定,全部 JDBC 4.0 的驅動 jar 文件必須包含一個 java.sql.Driver,它位於 jar 文件的 META-INF/services 目錄下。這個文件裏每一行便描述了一個對應的驅動類
在啓動項目或是服務時,會判斷當前classspath中的所的jar包,並檢查他們META-INF目錄下,是否包含services文件夾,若是包含,就會將裏面的配置加載成相應的服務。
META-INF/services/jdbc.sql.Driver文件內容爲須要加載的驅動,以下圖所示
image_5c3d32d7_4233
能夠打印出全部的已經加載的驅動程序,以下圖所示,與上圖文件中的不謀而合
image_5c3d32d7_55d0
 
因此,對於4.0前,使用Class.forName
4.0後咱們只須要將JAR包管理好就足夠了,這一切都會有人幫咱們完成(固然前提是須要使用配套的驅動Jar包)
 
完整的loadInitialDrivers方法
private static void loadInitialDrivers() { String drivers; try { //獲取環境變量中jdbc.drivers的列表
 drivers = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("jdbc.drivers"); } }); } catch (Exception ex) { drivers = null; } //若是按照規範在jar包中的META-INF/services設置了文件,將會加載爲服務 // If the driver is packaged as a Service Provider, load it. // Get all the drivers through the classloader // exposed as a java.sql.Driver.class service. // ServiceLoader.load() replaces the sun.misc.Providers()
 AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); Iterator<Driver> driversIterator = loadedDrivers.iterator(); /* Load these drivers, so that they can be instantiated. * It may be the case that the driver class may not be there * i.e. there may be a packaged driver with the service class * as implementation of java.sql.Driver but the actual class * may be missing. In that case a java.util.ServiceConfigurationError * will be thrown at runtime by the VM trying to locate * and load the service. * * Adding a try catch block to catch those runtime errors * if driver not available in classpath but it's * packaged as service and that service is there in classpath. */

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); } } }

 

簡言之,loadInitialDrivers主要作了兩件事情:
  • 讀取系統屬性jdbc.drivers,若是爲空就拉到,若是存在將會進行加載。
  • 檢查jar包中的META-INF/services,若是有那麼會自動註冊,服務註冊依賴的是ServiceLoader
 
對於加載的驅動程序,在前面已經說過,靜態代碼塊中,會完成註冊,而註冊就是添加到CopyOnWriteArrayList<DriverInfo> registeredDrivers中
image_5c3d32d7_657a
 

總結

驅動註冊就是加載數據庫的驅動程序,是使用JDBC進行數據庫操做的第一步。
JDBC的橋接模式,提供給應用程序開發者的API是抽象,這個驅動程序就是實現,若是不能進行成功註冊,就沒辦法提供後續的服務了,因此驅動註冊很重要。
以 JDBC4.0爲分水嶺
若是按照JDBC4.0後的規範,在jar包中設置了META-INF/services/jdbc.sql.Driver文件,而且寫入了驅動,那麼會自動加載
若是是以前的,則須要使用Class.forName()進行顯式加載。
自動加載依賴ServiceLoader.load(Driver.class);,其中關於目錄的設置是寫死的PREFIX = "META-INF/services/",想要深刻研究能夠翻閱ServiceLoader
image_5c3d32d8_4ca9
 
 

原文出處:https://www.cnblogs.com/noteless/p/10270107.htmlhtml

相關文章
相關標籤/搜索