前幾天看到一個文章中提出一個問題,在JDBC的開發中為什麼要使用Class.forName,可以不用這句嗎?
我們從代碼出發,來分析一下這個問題。
下面是一段我們常用的JDBC開發中的代碼(註:本文中例子使用Mysql為例子。為方便示範,代碼中忽略異常處理)
Class.forName("com.mysql.jdbc.Driver");<br />conn = DriverManager.getConnection(<br />"jdbc:mysql://localhost:3306/mysql", "root", "");<br />stmt = conn.createStatement();<br />rs = stmt.executeQuery("select count(0) from user");<br />while (rs != null && rs.next()) {<br />System.out.println(rs.getInt(1));<br />}
運行代碼,結果正常,列印出了Mysql資料庫中的使用者數。
我們先嘗試將第一句拿掉,看是不是也可以運行。
// 拿掉Class.forName語句,看一下運行結果<br />// Class.forName("com.mysql.jdbc.Driver");<br />conn = DriverManager.getConnection(<br />"jdbc:mysql://localhost:3306/mysql", "root", "");<br />stmt = conn.createStatement();<br />rs = stmt.executeQuery("select count(0) from user");<br />while (rs != null && rs.next()) {<br />System.out.println(rs.getInt(1));<br />}
運行代碼,報如下錯誤:
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/mysql<br />at java.sql.DriverManager.getConnection(DriverManager.java:602)<br />at java.sql.DriverManager.getConnection(DriverManager.java:185)<br />at net.moon.jdbc.demo.Demo.main(Demo.java:18)
看來是不行,那讓我們來分析一下,Class.forName(String clz)這樣一個方法到底做了什麼呢?
看一下API,API中Class.forName方法的聲明如下:
public static Class<?> forName(String className)<br /> 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");<br />// 建立一個Driver對象,同樣不關注返回的結果<br />new com.mysql.jdbc.Driver();<br />conn = DriverManager.getConnection(<br />"jdbc:mysql://localhost:3306/mysql", "root", "");<br />stmt = conn.createStatement();<br />rs = stmt.executeQuery("select count(0) from user");<br />while (rs != null && rs.next()) {<br />System.out.println(rs.getInt(1));<br />}
運行代碼,和預想的一樣,同樣可以得到運行結果。
我們再來想一下,com.mysql.jdbc.Driver這個類在初始化的時候到底執行了什嗎?先來回憶一下以前的一篇文章:Java牛角尖【003】:類初始化時的執行順序。明白了,好像有這樣一個概念:靜態代碼塊。
一定是在com.mysql.jdbc.Driver這個類中有一段靜態程式碼片段,這段代碼執行了某些動作。
之所以用Mysql做為例子,還有另外一個優點,那就是開源,開源也就是說我們可以看到它的代碼,所以下個任務就是找到com.mysql.jdbc.Driver這個類的源碼來看一下了。
代碼如下:
static {<br />try {<br />java.sql.DriverManager.registerDriver(new Driver());<br />} catch (SQLException E) {<br />throw new RuntimeException("Can't register driver!");<br />}<br />}
這段代碼似乎比我們想象的要簡單,是透過java.sql.DriverManager這個類的靜態方法registerDriver這個方法註冊這個JDBC驅動。
最後一個問題就是為什麼這裡要調用registerDriver方法呢,那就是來看一下DrvierManager的API了,如下:
registerDriver<br />public static void registerDriver(Driver driver)<br /> throws SQLException</p><p>向 DriverManager 註冊給定驅動程式。新載入的驅動程式類應該調用 registerDriver 方法讓 DriverManager 知道自己。 </p><p>參數:<br />driver - 將向 DriverManager 註冊的新的 JDBC Driver<br />拋出:<br />SQLException - 如果發生資料庫訪問錯誤
上一篇: Java牛角尖【011】: Java中只支援單繼承嗎?
下一篇:Java牛角尖【013】: finally塊中的代碼一定會執行嗎?