本文爲轉載學習java
原文連接:http://www.ticmy.com/?p=249mysql
獲取一個數據庫鏈接的通用模板以下:sql
String driver = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user = "scott"; String password = "ticmy"; Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, password);
裏面有個Class.forName(driver),這句話有什麼做用?將驅動類load到內存?若是沒有這句會怎麼樣?運行發現,若是去掉這一句會有如下異常:
java.sql.SQLException: No suitable driver found for xxx….數據庫
在解釋具體緣由以前先簡單看下Class.forName作了什麼。oracle
假設一個類之前歷來沒有被裝進內存過,Class.forName(String className)這個方法會作如下幾件事情:
一、裝載。將字節碼讀入內存,併產生一個與之對應的java.lang.Class類對象
二、鏈接。這一步會驗證字節碼,爲static變量分配內存,並賦默認值(0或null),並可選的解析符號引用(這裏不理解不要緊)
三、初始化。爲類的static變量賦初始值,假若有static int a = 1;這個將a賦值爲1的操做就是這個時候作的。除此以外,還要調用類的static塊。(這一步是要點)學習
Class.forName(String className)方法會將這三步都作掉,以下面的例子:測試
package com.ticmy.oracle; public class TestClinit { public static void main(String[] args) throws Exception { Class.forName("com.ticmy.oracle.ABC"); } } class ABC { private static int a = getNum(); static { System.out.println("this is static block"); } public static int getNum() { System.out.println("getNum"); return 1; } }
程序的運行結果是:
getNum
this is static blockui
那麼,Class.forName(driver)這個driver類裏有沒有什麼static塊呢?去探究一下。例子用的是Oracle,反編譯下oracle.jdbc.OracleDriver,發現其繼承了oracle.jdbc.driver.OracleDriver,那麼繼續看這個oracle.jdbc.driver.OracleDriver,確實有個static塊,裏面有這樣的代碼:this
static { Timestamp localTimestamp = Timestamp.valueOf("2000-01-01 00:00:00.0"); try { if (defaultDriver == null) { defaultDriver = new OracleDriver(); DriverManager.registerDriver(defaultDriver); } } catch (RuntimeException localRuntimeException) { } catch (SQLException localSQLException){} _Copyright_2004_Oracle_All_Rights_Reserved_ = null; }
再看看mysql吧:com.mysql.jdbc.Driver:
一樣發現了static塊,裏面代碼以下:url
static { try { DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
再看一個db2:com.ibm.db2.jcc.DB2Driver:
也發現了static塊:
static { if (o.Nb != null) { exceptionsOnLoadDriver__ = dg.a(o.Nb, exceptionsOnLoadDriver__); } try { registeredDriver__ = new DB2Driver(); DriverManager.registerDriver(registeredDriver__); } catch (SQLException localSQLException) { exceptionsOnLoadDriver__ = new SqlException(null, "Error occurred while trying to register Jcc driver with JDBC 1 Driver Manager"); exceptionsOnLoadDriver__.setNextException(localSQLException); } }
無一例外地,發現裏面都有DriverManager.registerDriver(driver)的調用。那麼是否是能夠將開頭的例子中的Class.forName換成DriverManager.registerDriver呢?
String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user = "scott"; String password = "ticmy"; DriverManager.registerDriver(new OracleDriver()); Connection conn = DriverManager.getConnection(url, user, password); System.out.println(conn); conn.close();
通過測試發現OK。如今,已經知道Class.forName(driver)的根本目的就是爲了調用DriverManager.registerDriver。
Class.forName還有個重載的方法:Class.forName(String name, boolean initialize, ClassLoader loader),Class.forName(String className)就等價於Class.forName(className, true, currentLoader),注意中間的參數爲true,這個參數的含義就是要不要初始化。若是此參數爲true且指定的類之前沒有被初始化過,就會去初始化。
另外,jdbc4已經不須要顯式的調用Class.forName了,在jdbc4中,調用getConnection的時候DriverManager會自動去加載合適的驅動。