使用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/
另外還有完整的文檔
oracle驅動下載
https://www.oracle.com/technetwork/database/application-development/jdbc/downloads/index.html
驅動注冊
在通過驅動管理器創建連接前需要進行驅動注冊
驅動注冊有三種形式
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");
- 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 或應用程序相同的類加載器顯式加載的那些驅動程序中查找合適的驅動程序。
JDBC 4.0 的規范規定,所有 JDBC 4.0 的驅動 jar 文件必須包含一個 java.sql.Driver,它位於 jar 文件的 META-INF/services 目錄下。這個文件里每一行便描述了一個對應的驅動類
在啟動項目或是服務時,會判斷當前classspath中的所的jar包,並檢查他們META-INF目錄下,是否包含services文件夾,如果包含,就會將里面的配置加載成相應的服務。
所以,對於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中
總結
驅動注冊就是加載數據庫的驅動程序,是使用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
原文地址:JDBC驅動程序注冊 JDBC簡介(二)