天天看點

Java牛角尖【012】: JDBC開發時為什麼要用Class.forName(““)

  前幾天看到一個文章中提出一個問題,在JDBC的開發中為什麼要使用Class.forName,可以不用這句嗎?

  我們從代碼出發,來分析一下這個問題。

  下面是一段我們常用的JDBC開發中的代碼(注:本文中例子使用Mysql為例子。為友善示範,代碼中忽略異常處理)

Class.forName("com.mysql.jdbc.Driver"); 
conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/mysql", "root", ""); 
stmt = conn.createStatement(); 
rs = stmt.executeQuery("select count(0) from user"); 
while (rs != null && rs.next()) { 
    System.out.println(rs.getInt(1)); 
}
           

  運作代碼,結果正常,列印出了Mysql資料庫中的使用者數。

  我們先嘗試将第一句拿掉,看是不是也可以運作。

 // 拿掉Class.forName語句,看一下運作結果 
// Class.forName("com.mysql.jdbc.Driver"); 
conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/mysql", "root", ""); 
stmt = conn.createStatement(); 
rs = stmt.executeQuery("select count(0) from user"); 
while (rs != null && rs.next()) { 
    System.out.println(rs.getInt(1)); 
}
           

  運作代碼,報如下錯誤:

java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/mysql at java.sql.DriverManager.getConnection(DriverManager.java:602) at java.sql.DriverManager.getConnection(DriverManager.java:185) at net.moon.jdbc.demo.Demo.main(Demo.java:18)
           

  看來是不行,那讓我們來分析一下,Class.forName(String clz)這樣一個方法到底做了什麼呢?

  看一下API,API中Class.forName方法的聲明如下:

 public static Class<?> forName(String className) throws ClassNotFoundException
           

  該方法是根據一個字元串,得到這個字元串所表示的類,但是我們上面代碼中并沒有一個引用指向這個傳回的結果,也就是代碼并不關注傳回的結果,那為什麼還要執行這句話呢,繼續往下看API中的說明,有這樣一句:“A call to forName("X") causes the class named X to be initialized”。

  問題似乎有點眉目了,原來在執行Class.forName("com.mysql.jdbc.Driver")這個語句時,com.mysql.jdbc.Driver這個類被初始化了,那一定是在初始化中做了什麼動作。為了證明這點,我們對上面的代碼做一點修改:

 // Class.forName("com.mysql.jdbc.Driver"); 
// 建立一個Driver對象,同樣不關注傳回的結果 
new com.mysql.jdbc.Driver(); 
conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/mysql", "root", ""); 
stmt = conn.createStatement(); 
rs = stmt.executeQuery("select count(0) from user"); 
while (rs != null && rs.next()) { 
    System.out.println(rs.getInt(1)); 
}
           

  運作代碼,和預想的一樣,同樣可以得到運作結果。

  我們再來想一下,com.mysql.jdbc.Driver這個類在初始化的時候到底執行了什麼?先來回憶一下以前的一篇文章:Java牛角尖【003】:類初始化時的執行順序。明白了,好像有這樣一個概念:靜态代碼塊。

  一定是在com.mysql.jdbc.Driver這個類中有一段靜态代碼段,這段代碼執行了某些動作。

  之是以用Mysql做為例子,還有另外一個優點,那就是開源,開源也就是說我們可以看到它的代碼,是以下個任務就是找到com.mysql.jdbc.Driver這個類的源碼來看一下了。

  代碼如下:

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

  這段代碼似乎比我們想象的要簡單,是透過java.sql.DriverManager這個類的靜态方法registerDriver這個方法注冊這個JDBC驅動。

  最後一個問題就是為什麼這裡要調用registerDriver方法呢,那就是來看一下DrvierManager的API了,如下:

 registerDriver public static void registerDriver(Driver driver) throws SQLException 向 DriverManager 注冊給定驅動程式。
新加載的驅動程式類應該調用 registerDriver 方法讓 DriverManager 知道自己。 
參數: 
    driver - 将向 DriverManager 注冊的新的 JDBC Driver 
抛出: 
    SQLException - 如果發生資料庫通路錯誤
           

  上一篇: Java牛角尖【011】: Java中隻支援單繼承嗎?

  下一篇:Java牛角尖【013】: finally塊中的代碼一定會執行嗎?