JDBC學習2:為什麼要寫Class.forName("XXX")?

五月的倉頡發表於2015-10-02

Class.forName(String name)

接上一篇JDBC。本來這個內容是放在前面的一篇裡面的一起的,後來發現越寫越多,想想看就算了,還是單獨開一篇文章好了,這樣也能寫得更加詳細點。

上一篇文章的第4點,getConnection()方法裡面,我把從.properties裡面獲取mysqlpackage的地方替換成實際的value值,那麼替換後的應該是Class.forName("com.mysql.jdbc.Driver"),實際上所有的JDBC連線先寫的基本上也都是這一句。另外,哪怕刪除這一句,也是可以執行成功的。那為什麼還要Class.forName("com.mysql.jdbc.Driver")呢?OK,分點講解。

1、為什麼要Class.forName("com.mysql.jdbc.Driver")?

JDBC是23種模式中的橋接模式的典型應用,熟悉橋接模式的基本上稍微看一下原始碼就知道為什麼了,那橋接模式這裡不講,只講為什麼要這麼做。Class.forName(String className)的作用有兩個,第一是CLASSPATH下指定名字的.class檔案載入到Java虛擬機器記憶體中, 第二是初始化這個類。看到這句話,返回值都沒有,那寫在這裡的作用很明顯了,就是初始化"com.mysql.jdbc.Drvier"。初始化做了什麼?給靜態資源賦值以及執行靜態程式碼塊,所以,反編譯一下"mysql-connector-java-5.1.20-bin.jar"這個jar包,檢視一下Driver類:

public class Driver extends NonRegisteringDriver
  implements java.sql.Driver
{
  public Driver()
    throws SQLException
  {
  }

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

看到Class.forName("com.mysql.jdbc.Driver")的作用實際上就是呼叫DriverManager的registerDriver方法註冊一個mysql的JDBC驅動(Driver)而已,Driver繼承NonRegisteringDriver.java,NonRegisteringDriver.java實現了JDK提供的Driver介面,這個Driver提供了若干資料庫連線的方法,每個不同的資料庫連線類都必須實現它,並重寫和具體的資料庫連線的演算法。DriverManager也是JDK中的類,截一些關鍵程式碼:

private static final CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList();
public static synchronized void registerDriver(Driver paramDriver)
    throws SQLException
  {
    if (paramDriver != null)
      registeredDrivers.addIfAbsent(new DriverInfo(paramDriver));
    else
      throw new NullPointerException();
    println("registerDriver: " + paramDriver);
  }

底層利用了一個CopyOnWriteArrayList作為容器(這是一個執行緒安全的容器,不過每次add的時候都會對底層陣列進行一次新的複製,所以在讀遠多於寫的時候建議可以使用這個),放那些註冊進去的DriverInfo。最終getConnection(...)的時候就拿registerDrivers裡面註冊進去的具體的某個資料庫的DriverInfo(像MySql的Driver就在DriverInfo裡面)去連線具體的資料庫。OK,所以總結一下整個流程:

JDK不負責和資料庫連線打交道,也沒必要,只提供一個具體的介面Driver,告訴所有第三方,要連線資料庫,就去實現這個介面,然後通過DriverManager註冊一下,到時候連線某個資料庫的時候,你已經在我這裡註冊了,我會呼叫你註冊進來的Driver裡面的方法去對指定資料庫進行連線的。然後Mysql就實現自己的Driver,Oracle就實現自己的Driver,通過static塊註冊一下,再然後,就沒有然後了。

2、為什麼不直接new?

意思是這麼寫"com.mysql.jdbc.Driver d = new com.mysql.jdbc.Driver();",可以啊,因為在new的時候會自動觸發對一個類的初始化。問題是new出來幹嘛?com.mysql.jdbc.Driver裡面的方法我們會用到嗎,並且我們知道怎麼用嗎?僅僅為了初始化一個類而new一個類例項出來還不如不去new,直接使用Class.forName(String name)初始化就可以了。DriverManager類的getConnection(...)方法的存在本身就是幫助使用者呼叫Driver裡面的各種方法連線資料庫,JDK都做好了,開發者就沒必要自己寫了。

3、為什麼刪除Class.forName("com.mysql.jdbc.Driver")還是可以執行?

1996年1月23日JDK1.0釋出,Java語言有了第一個正式版本的執行環境。JDBC是1997年2月19日,在JDK1.1的版本中釋出的,從版本就看得出,JDBC屬於Java技術的一些最基礎的功能點。那在JDK1.5之後,其實已經不需要去顯式呼叫Class.forName("com.mysql.jdbc.Driver")了,DriverManager會自動去載入合適的驅動,但是前提是CLASSPATH下必須有驅動jar包

相關文章