JDBC在getConnection之前為什麼要調用Class.forName(轉)

來源:互聯網
上載者:User

標籤:

擷取一個資料庫連接的通用模板如下:

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做了什麼。

假設一個類以前從來沒有被裝進記憶體過,Class.forName(String className)這個方法會做以下幾件事情:
1、裝載。將位元組碼讀入記憶體,併產生一個與之對應的java.lang.Class類對象
2、串連。這一步會驗證位元組碼,為static變數分配記憶體,並賦預設值(0或null),並可選的解析符號引用(這裡不理解沒關係)
3、初始化。為類的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 block

那麼,Class.forName(driver)這個driver類裡有沒有什麼static塊呢?去探究一下。例子用的是Oracle,反編譯下oracle.jdbc.OracleDriver,發現其繼承了oracle.jdbc.driver.OracleDriver,那麼繼續看這個oracle.jdbc.driver.OracleDriver,確實有個static塊,裡面有這樣的代碼:

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塊,裡面代碼如下:

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會自動去載入合適的驅動。
http://www.ticmy.com/?p=249

JDBC在getConnection之前為什麼要調用Class.forName(轉)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.