1. 程式人生 > >Class.forName載入資料庫驅動深入探討

Class.forName載入資料庫驅動深入探討

最近寫了個監控系統,需要從各個資料庫中獲取資料,為了可配行,各個資料庫的資訊(資料庫型別,使用者名稱,密碼等)都存放在我們自己的資料庫中,

暫時想到的方法就是直接用JDBC程式碼訪問資料庫,取資料,然後將資料庫連線進行池化。

唉,以前都是J2EE開發,用spring配置使用,這次直接使用JDBC還不太習慣了,OK,不廢話了

JDBC步驟:

1.載入資料驅動

Class.forName("com.mysql.jdbc.Driver");

 2. 得到資料庫連線

DriverManager.getConnection(url, user, password);

 當時到這步就產生兩個疑問:

1. 為什麼載入了資料庫驅動,就能得到資料庫連線,看上面的兩行程式碼,是看出來兩者之間聯絡

2. 除了Class.forName()載入資料庫驅動,貌似沒有看到過其他載入資料庫驅動方式,是否有其他方式?為什麼不用其他方式?

OK,問題出來了,就看看問題

問題1:

後來結合資料庫驅動原始碼和JDBC規範瞭解到,每個資料庫驅動,都必須在載入的時候,自己實現資料庫驅動註冊(註冊?貌似前面觀察者模式就有註冊行為,但是資料庫驅動卻沒有update行為,所以不存在通知)

mysql驅動原始碼:

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!");
     }
   }
 }

DriverManager.registerDriver()程式碼如下:

public static synchronized void registerDriver(java.sql.Driver driver)
	throws SQLException {
	if (!initialized) {
	    initialize();
	}
      
	DriverInfo di = new DriverInfo();

	di.driver = driver;
	di.driverClass = driver.getClass();
	di.driverClassName = di.driverClass.getName();

	// Not Required -- drivers.addElement(di);

	writeDrivers.addElement(di); 
	println("registerDriver: " + di);
	
	/* 由於可以註冊多個數據庫驅動型別,這裡更新下資料庫驅動 */
	readDrivers = (java.util.Vector) writeDrivers.clone();

    }
 

這樣在DriverManager.getConnection()的時候,就可以用到資料庫驅動,得到連線了,程式碼如下

public static Connection getConnection(String url, 
	String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();

        // Gets the classloader of the code that called this method, may 
	// be null.
	ClassLoader callerCL = DriverManager.getCallerClassLoader();

	if (user != null) {
	    info.put("user", user);
	}
	if (password != null) {
	    info.put("password", password);
	}

        return (getConnection(url, info, callerCL));
    }



private static Connection getConnection(
	String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
	java.util.Vector drivers = null;
        /*
	 * When callerCl is null, we should check the application's
	 * (which is invoking this class indirectly)
	 * classloader, so that the JDBC driver class outside rt.jar
	 * can be loaded from here.
	 */
	synchronized(DriverManager.class) {	 
	  // synchronize loading of the correct classloader.
	  if(callerCL == null) {
	      callerCL = Thread.currentThread().getContextClassLoader();
	   }    
	} 
	 
	if(url == null) {
	    throw new SQLException("The url cannot be null", "08001");
	}
    
	println("DriverManager.getConnection(\"" + url + "\")");
    
	if (!initialized) {
	    initialize();
	}

	synchronized (DriverManager.class){ 
            // 得到註冊的驅動
	    drivers = readDrivers;  
        }

	// Walk through the loaded drivers attempting to make a connection.
	// Remember the first exception that gets raised so we can reraise it.
	SQLException reason = null;
	for (int i = 0; i < drivers.size(); i++) {
	    DriverInfo di = (DriverInfo)drivers.elementAt(i);
      
	    // 根據資料庫型別判斷,得到這次請求的資料庫連線
	    if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
		println("    skipping: " + di);
		continue;
	    }
	    try {
		println("    trying " + di);
		Connection result = di.driver.connect(url, info);
		if (result != null) {
		    // Success!
		    println("getConnection returning " + di);
		    return (result);
		}
	    } catch (SQLException ex) {
		if (reason == null) {
		    reason = ex;
		}
	    }
	}
    
	// if we got here nobody could connect.
	if (reason != null)    {
	    println("getConnection failed: " + reason);
	    throw reason;
	}
    
	println("getConnection: no suitable driver found for "+ url);
	throw new SQLException("No suitable driver found for "+ url, "08001");
    }
 

OK,到此問題的答案算是明白了

下面,問題2:

載入類的方式幾種,目前我想到的就下面幾種,不夠以後在補充,呵呵:

1. Class.forName()

2. Class.forName().newInstance();

3. new

4.Class.class

5.Class.class.newInstance();

6.Thread.currentThread().getContextClassLoader().loadClass()

可以知道方法2和5都是有點多餘,載入的類,還例項化了一個物件出來,可以Pass掉。而3跟前面一個問題一樣,例項化了一個物件出來,多此一舉,此物件還佔據記憶體。

OK,還剩下三種方法1.4.6,先來分析1和6的區別

Class.forName()的原始碼如下:

public static Class<?> forName(String className) 
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }

 呼叫此方法等效於:

  Class.forName(className, true, currentLoader)

第二次引數表示裝載類的時候是否初始化該類, 即呼叫類的靜態塊的語句及初始化靜態成員變數。

Thread.currentThread().getContextClassLoader().loadClass()的程式碼如下:

public Class<?> loadClass(String name) throws ClassNotFoundException {
	return loadClass(name, false);
    }
 
protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClassOrNull(name);
		}
	    } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }
            if (c == null) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }
  此方法使用指定的二進位制名稱來載入類。此方法的預設實現將按以下順序搜尋類:

如果使用上述步驟找到類,並且 resolve 標誌為真,則此方法將在得到的 Class 物件上呼叫 resolveClass(Class) 方法。

引數:
resolve - 如果該引數為 true,則分析這個類 

所以此方法沒有初始化類,即沒有載入類的靜態程式碼,所以此方法不行

OK,下面只剩下方法1和4了,方法4載入類會獲得編譯檢查,可以保證此類一定存在,所以無法做到執行時動態載入未知資料庫驅動,並且Class.class前面還必須給一個變數賦值才行: Class cc = Class.class

所以載入資料庫,大家看到的都是方法1。

好了,到這,收工,呵呵。。。。

相關推薦

Class.forName載入資料庫驅動深入探討

最近寫了個監控系統,需要從各個資料庫中獲取資料,為了可配行,各個資料庫的資訊(資料庫型別,使用者名稱,密碼等)都存放在我們自己的資料庫中, 暫時想到的方法就是直接用JDBC程式碼訪問資料庫,取資料,然後將資料庫連線進行池化。 唉,以前都是J2EE開發,用spring配置使用,

為什麼使用Class.forName("")載入資料庫驅動

Class.forName(“”)返回的是類     Class.forName(“”).newInstance()返回的是object     有資料庫開發經驗朋友會發現,為什麼在我們載入資料庫驅動包的時候有的卻沒有呼叫newInstance( )方法呢?

載入資料庫驅動的方法Class.forName()看其作用!

使用JDBC時,我們都會很自然得使用下列語句: java 程式碼 Class.forName("com.mysql.jdbc.Driver");    String url = "jdbc:mysql://127.0.0.1/test?useUnicode=true&am

Class.forName 如何載入資料庫驅動

一直有一個疑問,Class.forName(driverName)是如何完成載入資料庫驅動的,查閱了Oracle驅動的原始碼之後,大體弄清楚了。 我們知道,Class.forName所做的工作是載入指定的class檔案到java虛擬機器的記憶體,載入class檔案到記憶體的時候,該class檔案的靜態變數和

springboot啟動不能載入資料庫驅動Failed to determine a suitable driver class

1 SLF4J: Class path contains multiple SLF4J bindings. 2 SLF4J: Found binding in [jar:file:/G:/sharp/repo/ch/qos/logback/logback-classic/1.2.3/logback-

java Class.forName() 載入

主要功能 Class.forName(xxx.xx.xx)返回的是一個類。 Class.forName(xxx.xx.xx)的作用是要求JVM查詢並載入指定的類,也就是說JVM會執行該類的靜態程式碼段。 在指定類給 forName() 方法後,如果找不到指定的類,會丟擲 ClassNo

Java反射中Class.forName()載入類和使用ClassLoader載入類的區別

最近在面試過程中有被問到,在Java反射中Class.forName()載入類和使用ClassLoader載入類的區別。當時沒有想出來後來自己研究了一下就寫下來記錄一下。 解釋 在java中Class.forName()和ClassLoader都可以對類進行載入。ClassLoader就是遵

[瘋狂Java]JDBC:載入資料庫驅動、連線資料庫

1. 載入資料庫驅動:     1) 由於Java是一個純面嚮物件語言,任何事物在其中都必須抽象成類或者類物件,資料庫也不例外,JDBC同樣也把資料庫抽象成面向物件的結構;     2) JDBC將整個資料庫驅動器在底層抽象成一個物件(即驅動器物件),所有對資料庫的操作都可

javaEE 中jdbc載入資料庫驅動失敗

jdbc連結mysql資料庫的時候            Class.forName("com.mysql.jdbc.Driver"); 這句報ClassNotFoundException,網上找了一下,這篇部落格講的非常實用,推薦給大家 http://blog.csdn.

thinkphp無法載入資料庫驅動: Think\Db\Driver\

今天做專案的時候加了配置檔案導致這個問題 很懵逼,上午跑的好好地, 1.首先在你輸出的頁面var_dump(C());  打印出頁面載入的東西,檢視結果中是否缺失DB_TYPE等資料庫連線資料 最後

Java載入資料庫連線驅動為什麼要用Class.forName()方法?

靜態初始化過程,可以閱讀一下Thinking in Java 2nd 的第5-8章 JDBC提供的DriverManager類用於跟蹤所有可用的JDBC驅動,並在使用者需要時選擇合適的驅動提供給使用者 但是其跟蹤不是自動的,必須由可用的JDBC驅動

JDBC不再需要Class.forName()來顯式載入jdbc驅動

最近在用jdbc操作資料庫時,發現沒有Class.forName("com.mysql.jdbc.Driver")這一句,也可以連上資料庫並操作。後來在java.sql.DriverManager類中找到了這行註釋 * <P>Applications no lon

關於Java連線mysql資料庫驅動載入

第一步準備工作: 在官網https://dev.mysql.com/downloads/connector/j/下載mysql驅動   下載完後開啟資料夾   複製mysql-connector-java-8.0.13.jar檔案 第二步開啟e

Java中的類載入Class.forName();java反射機制與原理

對於大部分人來說,第一次見到class.forName(String className)這句程式碼應該是在使用jdbc方式連線資料庫的時候。但這句程式碼本質上是什麼含義,做了什麼工作呢?本文將回答此問題。 理解Class.forName方法需要一些知識鋪墊,也就是

重新安裝了tomcat導致資料庫驅動載入不成功的解決方案

今天我運行了一下我的登入專案,發現執行不成功,加了斷點發現是驅動載入問題,想起了我昨天把tomcat解除安裝重灌,可能是重灌了以後把原本路徑下的jar包刪除了,但是我換了路徑build path了也不行,搞了半天也不知道為啥,我之前的一個application專案也用到資料庫

深入探討 Java 類載入

類載入器是 Java 語言的一個創新,也是 Java 語言流行的重要原因之一。它使得 Java 類可以被動態載入到 Java 虛擬機器中並執行。類載入器從 JDK 1.0 就出現了,最初是為了滿足 Java Applet 的需要而開發出來的。Java Applet 需要從

spring boot 資料庫驅動 maven載入問題

問題描述:在2.0之後版本的spring boot 引用一些資料庫驅動會發現無法識別,再去maven下檢視會發現驅動未下載。 經過我的勘察,發現原來是因為,新版本的依賴 <parent> <groupId>org.springframewo

JDBC 連線資料庫Class.forName的作用

JAVA課上交過jdbc連線資料庫。可是老師也沒說當中 這樣的程式碼是什麼意思:Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection(URL);很久前 看到一個面試題 大概也是問這幾

Java 類載入機制 ClassLoader Class.forName 記憶體管理 垃圾回收GC

類載入是Java程式執行的第一步,研究類的載入有助於瞭解JVM執行過程,並指導開發者採取更有效的措施配合程式執行。 研究類載入機制的第二個目的是讓程式能動態的控制類載入,比如熱部署等,提高程式的靈活性和適應性。 一、簡單過程 Java

註冊 Jdbc 驅動程式的三種方式及Class.forName 的作用

(1)jdbc中註冊驅動,首先匯入對應的包,例如mysql-connector-java-5.0.8-bin.jar。驅動包是java和具體資料庫之間的連線橋樑,由資料庫廠商開發。每一種資料庫對應一款驅動jar,甚至每一個版本的資料庫都有自己對應版本的驅動jar。 (2