一、注冊方法(4種)
1)服務提供者框架:
符合JDBC 4.0規范的驅動程序包含了一個文件META-INF/services/java.sql.Driver,在這個文件中提供了JDBC驅動實現的類名。
例如:mysql-connector-java-5.1.40-bin.jar文件中就可以找到java.sql.Driver文件,用文本編輯器打開文件就可以看到:com.mysql.jdbc.Driver類。
JVM的服務提供者框架在啟動應用時就會注冊服務,例如:mySQL的JDBC驅動就會被注冊,而原代碼中的Class.forName("com.mysql.jdbc.Driver")仍然可以存在,但是不會起作用。
2)Class.forName("com.mysql.jdbc.Driver");
通過對類com.mysql.jdbc.Driver初始化,執行靜態初始化代碼,調用DriverManager注冊JDBC驅動。
注:通過setProperty的測試,確認類com.mysql.jdbc.Driver也沒有加載,那么靜態初始化代碼肯定被執行了,但是如果服務提供者框架已經注冊的服務,這里注冊會失敗,編程的預期是這樣的,可是理論上DriverManager.registerDriver可以重復注冊的,為什么這里不能重復注冊呢?
3)System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver";);
設置JVM的系統屬性,當JVM第一次加載DriverManager類時,會執行類的靜態初始化代碼,代碼中調用loadInitialDrivers()方法,就會加載設置的屬性對應的類,執行類的靜態初始化代碼完成注冊。
注:因為注冊的機制無法深入理解,只知道沒有加載過的類可以注冊成功,加載過的就不能重復注冊了。
注:setProperty必須在DriverManager第一次運行前才有效,說明”服務提供者”框架注冊服務時并沒有加載類,因為一旦加載類就會執行類的靜態初始化代碼,那么注冊JDBC驅動就一定會調用DriverManager類的靜態初始化代碼,那么setProperty就會失效,所以說明注冊服務是不加載類的。
4)DriverManager.registerDriver(new com.mysql.jdbc.Driver());
其實前面的2)和3)最終都是通過這個方法注冊的,但是這個方法就可以重復注冊。
注:對于重復注冊后,建立鏈接時使用哪個驅動我就不明白了,可以取消注冊,取消的關鍵字是基于創建的對象的,所以就算重名也不會出錯。
注:這種注冊方式沒有前面幾種好,因為這種注冊方式會在代碼中與需要注冊的驅動程序的類綁定,前面都可以通過配置參數實現注冊。
二、各自特點:
1)全自動。只要提供符合規范的JAR文件就可以了。
2)利用反射機制,將驅動類注入到代碼中,不需要與代碼綁定。
3)基于系統的屬性設置方法,將驅動類注入到代碼中,但是好像只能綁定一個JDBC驅動。
4)最終的注冊機制。會出現重復注冊,但是好像對程序沒影響,還需要與代碼綁定,驅動變了,必須修改代碼,維護成本過高,當然也是靈活性最好,管理最方便的。
以下是測試代碼:
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
/**
* @author 朱遠翔.Tom 測試JDBC驅動注冊
*/
public class JDBCDriverTest {
public static void main(String[] args) {
Driver aDriver;
Connection connection;
Enumeration em;
// “org.gjt.mm.mysql.Driver”是“com.mysql.jdbc.Driver”的子類,其構造函數就是調用父類的構造函數。
String driverString = "com.mysql.jdbc.Driver";
// String driverString = "org.gjt.mm.mysql.Driver";
String url = "jdbc:mysql://localhost/ElectricalStore?useSSL=false";
String username = "admin";
String password = "123456";
try {
// 將DriverManager的日志流輸出到Console窗口中,方便監控
// DriverManager.setLogStream(System.out);
// DriverManager.println("------DriverManager logs start!------");
// 只是設置了一個JVM的系統屬性,并不建立JDBC驅動程序。
// 建立JDBC驅動是依賴系統第一次調用DriverManager類時,執行了這個類的靜態初始化代碼中的loadInitialDrivers(),
// 加載驅動的方法會把設置的jdbc.drivers屬性對應的驅動類通過DriverManager.registerDriver注冊到JDBC中。
// 因此,必須放在DriverManager被第一次調用之間,也就是需要將前面那兩行代碼注釋掉
System.out.println("1.1> Tried to use setProperty.");
System.setProperty("jdbc.drivers", driverString);
System.out.println("---List of all jdbc drivers---");
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
if (!em.hasMoreElements()) {
System.out.println("There is no JDBC drivers");
} else {
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
System.out.println(aDriver);
}
}
System.out.println("1.2> we tried to use Class.forName");
// Class.forName(driverString)在JavaSE 6.0后符合JDBC 4.0規范的驅動可以不用
// 基于服務提供機制( Service Provider mechanism),
// 系統會自動搜索mysql-connector-java-???-bin.jar中的META-INF/services/java.sql.Driver
// 這個文件會包含mysql jdbc驅動程序的入口:com.mysql.jdbc.Driver
// 應用程序調用Class.forName()也不會出錯,只是什么都不會執行。
// 因為Class.forName()就是執行靜態初始化代碼,已經初始化過的類就無法激活這段代碼了
// System.setProperty("jdbc.drivers",driverString);與Class.forName()一樣。
try {
Class.forName("com.mysql.fabric.jdbc.FabricMySQLDriver");
} catch (ClassNotFoundException e) {
System.out.println("Driver not found");
}
System.out.println("---List of all jdbc drivers---");
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
if (!em.hasMoreElements()) {
System.out.println("There is no JDBC drivers");
} else {
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
System.out.println(aDriver);
}
}
System.out.println("1.3> we tried to use DriverManager.registerDriver");
// 手工注冊mySQL的JDBC驅動程序,也就出現了與mySQL綁定過緊的問題,如果以后需要更換驅動,就需要修改代碼。
// 系統容許出現重復注冊同樣的jdbc驅動類
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
DriverManager.registerDriver(new com.mysql.fabric.jdbc.FabricMySQLDriver());
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
System.out.println("---List of all jdbc drivers---");
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
System.out.println(aDriver);
}
System.out.println("<1.5> Deregister all JDBC drivers");
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
DriverManager.deregisterDriver(aDriver); // 將已經注冊的驅動程序取消注冊
}
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
if (!em.hasMoreElements()) {
System.out.println("2.1> Now, there is no JDBC driver");
}
System.out.println("2.2> we tried to use Class.forName again");
try {
Class.forName(driverString);
} catch (ClassNotFoundException e) {
System.out.println("Driver not found");
}
try {
Class.forName("com.mysql.fabric.jdbc.FabricMySQLDriver");
} catch (ClassNotFoundException e) {
System.out.println("Driver not found");
}
try {
Class.forName(driverString);
} catch (ClassNotFoundException e) {
System.out.println("Driver not found");
}
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
if (!em.hasMoreElements()) {
System.out.println("There is no JDBC drivers");
} else {
System.out.println("---List of all jdbc drivers---");
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
System.out.println(aDriver);
}
}
System.out.println("2.3> we tried to use setProperty again");
System.setProperty("jdbc.drivers", "com.mysql.fabric.jdbc.FabricMySQLDriver");
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
if (!em.hasMoreElements()) {
System.out.println("There is no JDBC drivers");
} else {
System.out.println("---List of all jdbc drivers---");
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
System.out.println(aDriver);
}
}
System.out.println("2.3> Tried to use DriverManager.registerDriver again");
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
DriverManager.registerDriver(new com.mysql.fabric.jdbc.FabricMySQLDriver());
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
System.out.println("---List of all jdbc drivers---");
em = DriverManager.getDrivers(); // 獲取已加載JDBC驅動程序的Enumeration
if (!em.hasMoreElements()) {
System.out.println("There is no JDBC drivers");
} else {
while (em.hasMoreElements()) {
aDriver = (Driver) em.nextElement();
System.out.println(aDriver);
}
}
System.out.print("3.1> Tried to establish a connection: ");
connection = DriverManager.getConnection(url, username, password);
System.out.println(connection);
} catch (SQLException e) {
System.out.println("Cannot registered the mysql jdbc driver");
}
System.out
.println("jdbc.drivers property: " + System.getProperty("jdbc.drivers", "nothing"));
}
}