Class.forName("com.mysql.jdbc.Driver") 是個什麼鬼?
一句話總結這行程式碼的功能:將mysql驅動註冊到DriverManager中去。
那麼為什麼可以通過這行程式碼實現註冊driver功能呢? 答: 通過呼叫這個方法,就可以將mysql的驅動driver類的class檔案載入到記憶體中; 又由於載入類檔案會執行其中的靜態程式碼塊,此時就會將mysql的driver註冊到系統的DriverManager中。
我們首先看forName方法的原始碼:
public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
我們可以看到返回值是 Class<?>,即我們將mysql的驅動類→driver類載入到了 記憶體中。 我們知道,當類被載入到記憶體中時,會首先執行類的靜態程式碼塊中的內容,那我們接下來就看看Driver類的原始碼,看看它被載入到記憶體中時,到底執行了什麼內容。 我們找到com.mysql.jdbc.Driver類:
public class Driver extends NonRegisteringDriver implements java.sql.Driver { public Driver() throws SQLException { } static { try { //1. 新建一個mysql的driver物件 //2. 將這個物件註冊到DriverManager中 DriverManager.registerDriver(new Driver()); } catch (SQLException var1) { throw new RuntimeException("Can't register driver!"); } } }
可以看到,靜態程式碼塊中執行的內容是:新建一個msql的driver物件,並將其註冊到DriverManager中去。
接下來我們再看看這個DriverManager.registerDriver 方法,先看這個方法的說明:
- 將引數中的driver註冊到DriverManager中。
- 新載入的驅動類,應該通過呼叫這個方法來將自己註冊到DriverManager中。
- 如果這個驅動已經被註冊,那麼將不會做任何動作。
/** * Registers the given driver with the {@code DriverManager}. * A newly-loaded driver class should call * the method {@code registerDriver} to make itself * known to the {@code DriverManager}. If the driver is currently * registered, no action is taken. * * * */ public static void registerDriver(java.sql.Driver driver) throws SQLException { //它實際呼叫了自身的registerDriver方法 registerDriver(driver, null); }
繼續看這個registerDriver(driver, null);方法
//支援併發的arraylist
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
......
public static void registerDriver(java.sql.Driver driver, DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if (driver != null) {
//如果該驅動尚未註冊,那麼將他新增到 registeredDrivers 中去。這是一個支援併發情況的特殊ArrayList
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
registeredDrivers.addIfAbsent(new DriverInfo(driver, da)) 表示:如果該驅動尚未註冊,那麼將他新增到 registeredDrivers 中去。從類中的宣告來看這是一個支援併發情況的特殊ArrayList。
此時,Class.forName(“com.mysql.jdbc.Driver”) 的工作就完成了,這一行程式碼的工作就是:將mysql驅動註冊到DriverManager中去
DriverManager.getConnection方法分析
註冊的DriverManager中之後,我們就可以 通過DriverManager的getConnection方法獲得mysql的連線了:
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
接下來我們在看看這個getConnection方法:
@CallerSensitive
public static Connection getConnection(String url,
String user, String password) throws SQLException {
......
return (getConnection(url, info, Reflection.getCallerClass()));
}
同樣,呼叫了自身的 getConnection方法;繼續往裡看
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
......
for (DriverInfo aDriver : registeredDrivers) {
......
Connection con = aDriver.driver.connect(url, info);
......
}
}
可以看到它對上文提到的特殊ArrayList進行了遍歷,呼叫了driverinfo.driver的connect(url, info); 方法,這是一個介面,由各個不同的驅動自己實現。
/**
* Attempts to make a database connection to the given URL.
* The driver should return "null" if it realizes it is the wrong kind
* of driver to connect to the given URL. This will be common, as when
* the JDBC driver manager is asked to connect to a given URL it passes
* the URL to each loaded driver in turn.
*/
Connection connect(String url, java.util.Properties info)
throws SQLException;
到此為止,我們就獲得了connection物件,現在就可以對資料庫進行操作了。