解決JDBC的class.forName()問(wèn)題
環(huán)境
- Ubuntu 22.04
- IntelliJ IDEA 2022.1.3
- JDK 17.0.3
- Db2 v11.5.0.0
- MySQL Ver 8.0.30
準(zhǔn)備
Db2
在Db2的 sample 數(shù)據(jù)庫(kù)中,創(chuàng)建表 t1 ,并插入一些數(shù)據(jù)。如下:
? ~ db2 "select * from t1"
C1 C2 C3
----------- ----------- -----------
1 444 -
2 222 -
3 333 -
3 record(s) selected.
MySQL
在MySQL的 repo 數(shù)據(jù)庫(kù)中,創(chuàng)建表 t1 ,并插入一些數(shù)據(jù)。如下:
mysql> select * from t1; +------+-------+ | c1 | c2 | +------+-------+ | 1 | 9800 | | 2 | 10200 | +------+-------+ 2 rows in set (0.00 sec)
代碼
創(chuàng)建Maven項(xiàng)目 test0924 。
修改 pom.xml 文件,添加依賴:
......
<!-- https://mvnrepository.com/artifact/com.ibm.db2/jcc -->
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<version>11.5.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
......
如上,在項(xiàng)目添加了Db2和MySQL的JDBC驅(qū)動(dòng)。
Db2
創(chuàng)建類 Test0924_Db2 :
package pkg1;
import java.sql.*;
public class Test0924_Db2 {
public static void main(String[] args) throws ClassNotFoundException {
// Class.forName("com.ibm.db2.jcc.DB2Driver");
try (
Connection connection = DriverManager.getConnection("jdbc:db2://localhost:50000/sample",
"db2inst1", "passw0rd");
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("select * from t1");
) {
// System.out.println(connection.getClass().getName());
while (rs.next()) {
System.out.println(rs.getInt(1));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
運(yùn)行程序,結(jié)果如下:
1
2
3
MySQL
創(chuàng)建類 Test0924_Mysql :
package pkg1;
import java.sql.*;
public class Test0924_Mysql {
public static void main(String[] args) throws ClassNotFoundException {
// Class.forName("com.mysql.jdbc.Driver");
try (
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/repo",
"root", "123456");
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("select * from t1");
) {
// System.out.println(connection.getClass().getName());
while (rs.next()) {
System.out.println(rs.getInt(1));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
運(yùn)行程序,結(jié)果如下:
1
2
分析
JDBC
比較兩個(gè)Java文件可見(jiàn),連接Db2和連接MySQL的方式非常類似,唯一的區(qū)別在于,調(diào)用 DriverManager.getConnection() 方法時(shí),傳入的URL不同:
- Db2:
jdbc:db2://localhost:50000/sample - MySQL:
jdbc:mysql://localhost:3306/repo
更確切的說(shuō),只是協(xié)議的不同: db2 VS. mysql 。
我們知道,JDBC是一套標(biāo)準(zhǔn),各個(gè)廠商分別有著自己的實(shí)現(xiàn),也就是各自的JDBC驅(qū)動(dòng)。這也就是為什么一開(kāi)始,我們就先引入Db2和MySQL的JDBC驅(qū)動(dòng)。
JDBC中幾個(gè)重要的類:
java.sql.DriverManagerjava.sql.Connectionjava.sql.Statementjava.sql.ResultSet
注意: Connection 、 Statement 、 ResultSet 都是需要關(guān)閉的,一種方法是在 finally 塊里顯式調(diào)用其 close() 方法。本例中,使用了Java 7引入的 try() 塊來(lái)自動(dòng)釋放資源(它們都實(shí)現(xiàn)了 AutoCloseable 接口)。
class.forName()
以前我們學(xué)習(xí)JDBC的時(shí)候,被告知第一步要先使用 Class.forName() 方法,導(dǎo)入特定的JDBC驅(qū)動(dòng)。
但是通過(guò)本文的兩個(gè)例子,我們看到,即使省略這一步,也沒(méi)有問(wèn)題,DriverManager能夠自動(dòng)找到合適的驅(qū)動(dòng)。
那么問(wèn)題來(lái)了:
- 調(diào)用
Class.forName()方法,到底干了什么? - 為什么本文中不調(diào)用該方法也沒(méi)問(wèn)題?
我們知道,如果某個(gè)類之前沒(méi)有被使用過(guò),則調(diào)用 Class.forName() 方法,會(huì)做幾件事情,包括實(shí)例化該類的Class對(duì)象,并且執(zhí)行其static塊,等等。
對(duì)于JDBC驅(qū)動(dòng),以Db2驅(qū)動(dòng)為例,查看 com.ibm.db2.jcc.DB2Driver 類,可以找到如下代碼:
static {
DB2BaseDataSource.class.getClass();
try {
registeredDriver__ = new DB2Driver();
DriverManager.registerDriver(registeredDriver__);
} catch (SQLException var1) {
ap.f = lr.a(b7.a(DB2Driver.class, (ds)null, ErrorKey.ERROR_REGISTER_WITH_DRIVER_MGR, "10032"), ap.f);
}
}
可見(jiàn),調(diào)用了 DriverManager.registerDriver() 方法注冊(cè)了Db2的驅(qū)動(dòng)。
同理,對(duì)于MySQL,它的驅(qū)動(dòng)類 com.mysql.cj.jdbc.Driver (是 com.mysql.jdbc.Driver 類的父類)里有如下代碼:
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
可見(jiàn),類似的,也是調(diào)用了 DriverManager.registerDriver() 方法注冊(cè)了MySQL的驅(qū)動(dòng)。
由此,我們知道,調(diào)用 class.forName() 方法來(lái)裝載驅(qū)動(dòng),其作用是注冊(cè)了該驅(qū)動(dòng)。
那么為什么本文中不調(diào)用方法也沒(méi)問(wèn)題呢?
java.sql.Connection 是一個(gè)接口,我們通過(guò)打印 connection.getClass().getName() 來(lái)看看具體的類名(參見(jiàn)代碼中的注釋部分)。
- Db2:
com.ibm.db2.jcc.t4.b - MySQL:
com.mysql.cj.jdbc.ConnectionImpl
可見(jiàn),即使不通過(guò) class.forName() 方法來(lái)顯式注冊(cè)指定的驅(qū)動(dòng),而直接調(diào)用 DriverManager.getConnection() 方法,則根據(jù)傳入的URL不同,也能獲取正確的數(shù)據(jù)庫(kù)連接。
可以去查看DriverManager的源碼,大致如下:
......
for (DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if (isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
......
也就是說(shuō),它會(huì)先生成驅(qū)動(dòng)的列表,然后遍歷列表,根據(jù)傳入的URL,嘗試使用當(dāng)前驅(qū)動(dòng)來(lái)連接數(shù)據(jù)庫(kù),如果能連上,就OK,否則就嘗試下一個(gè)驅(qū)動(dòng)。
當(dāng)然,如果調(diào)用 Class.forName() 方法顯式注冊(cè)驅(qū)動(dòng),則會(huì)把驅(qū)動(dòng)類放到列表的第一個(gè),優(yōu)先使用它來(lái)連接數(shù)據(jù)庫(kù)。
到此這篇關(guān)于關(guān)于JDBC的class.forName()問(wèn)題的文章就介紹到這了,更多相關(guān)JDBC的class.forName()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析SQL Server 視圖、數(shù)據(jù)庫(kù)快照
在程序開(kāi)發(fā)過(guò)程中,任何一個(gè)項(xiàng)目都離不開(kāi)數(shù)據(jù)庫(kù),這篇文章給大家詳細(xì)介紹SQL Server 視圖、數(shù)據(jù)庫(kù)快照相關(guān)內(nèi)容,需要的朋友可以參考下2015-08-08
Can''t connect to local MySQL through socket ''/tmp/mysql.so
今天小編就為大家分享一篇關(guān)于Can't connect to local MySQL through socket '/tmp/mysql.sock'解決方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
使用MySQL進(jìn)行千萬(wàn)級(jí)別數(shù)據(jù)查詢的技巧分享
這篇文章主要介紹了如何使用MySQL進(jìn)行千萬(wàn)級(jí)別數(shù)據(jù)查詢的技巧,文中通過(guò)代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-03-03
CentOS7.x?安裝mysql5.7?XtraBackUp備份工具使用命令詳解
這篇文章主要介紹了CentOS7.x?安裝mysql5.7?XtraBackUp備份工具使用,本文給大家介紹了mysql安裝過(guò)程及命令使用方法,需要的朋友可以參考下2022-04-04
安裝MySQL phpMyAdmin cpolar實(shí)現(xiàn)遠(yuǎn)程訪問(wèn)連接的操作步驟
這篇文章主要給大家介紹了安裝 MySQL phpMyAdmin cpolar實(shí)現(xiàn)遠(yuǎn)程訪問(wèn)連接的流程步驟,文中有詳細(xì)的圖文介紹,具有一定的參考價(jià)值,需要的朋友可以參考下2023-08-08

