JDBC全稱Java Database Connectivity,是Java官方定義的一套連接數(shù)據(jù)庫(kù)的規(guī)范,里面包括各種API,其中最重要的就是關(guān)于如何獲取數(shù)據(jù)庫(kù)連接Connection的方法:
- 直接調(diào)用DriverManager類的getConnection方法
- 實(shí)現(xiàn)DataSource接口,調(diào)用實(shí)例的getConnection方法
DriverManager
初學(xué)JDBC的時(shí)候,每個(gè)同學(xué)首先都會(huì)接觸以下的代碼,步驟很簡(jiǎn)單,就是先注冊(cè)相應(yīng)數(shù)據(jù)庫(kù)的JDBC Driver,然后通過(guò)JDBC DriverManager獲取數(shù)據(jù)庫(kù)連接,之后從連接中執(zhí)行SQ語(yǔ)句。
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(DB_URL,USER,PASS);
Statement stmt = conn.createStatement();
String sql;
sql = "SELECT id, first, last, age FROM Employees";
ResultSet rs = stmt.executeQuery(sql);
...
JDBC規(guī)范規(guī)定Driver類在加載時(shí)必須向DriverManager類注冊(cè)自己的實(shí)例,例如MySQL實(shí)現(xiàn)的Driver類在類加載的時(shí)候執(zhí)行static代碼塊,將Driver實(shí)例注冊(cè)在DriverManager類中,DriverManager類會(huì)維護(hù)一個(gè)CopyOnWriteArrayList來(lái)保存所有被注冊(cè)的Driver。
package com.mysql.jdbc;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}
java.sql.Driver是個(gè)接口類,其中最重要的是connect(String url, Properties info)方法,應(yīng)用程序在調(diào)用DriverManager的getConnection方法時(shí),內(nèi)部會(huì)遍歷所有的Driver來(lái)使用傳遞的URL去嘗試連接數(shù)據(jù)庫(kù),直到連接成功然后返回Connection實(shí)例。所以,Driver是獲取數(shù)據(jù)庫(kù)連接真正的類,每個(gè)數(shù)據(jù)庫(kù)廠商都在Driver.connect(String url, Properties info)里面封裝了自己的內(nèi)部實(shí)現(xiàn)邏輯,比如MySQL在connect方法內(nèi)部實(shí)現(xiàn)MySQL協(xié)議來(lái)和遠(yuǎn)程MySQL服務(wù)端建立TCP連接。
DataSource
JDBC規(guī)范提供了一個(gè)更加靈活的獲取Connection的方式,即DataSource接口,DataSource接口規(guī)定了必須實(shí)現(xiàn)getConnection等方法。由于這種方式比DriverManager更加抽象,用戶可以自己實(shí)現(xiàn)獲取Connection的方式,在應(yīng)用層也無(wú)需知道連接究竟是如何獲取的,所以在實(shí)際應(yīng)用中,人們往往基于DataSource來(lái)實(shí)現(xiàn)連接池、分庫(kù)分表中間件的功能。
DataSource : This interface is preferred over DriverManager
because it allows details about the underlying data source to be transparent to your application. A DataSource
object's properties are set so that it represents a particular data source. See Connecting with DataSource Objects for more information. For more information about developing applications with the DataSource
class, see the latest The Java EE Tutorial.
雖然有了DataSource,但是數(shù)據(jù)庫(kù)廠商依然要提供上述的Driver,因?yàn)橥ㄟ^(guò)Driver連接數(shù)據(jù)庫(kù)的方式是物理層連接,必不可少,所有的DataSource最底層建立物理連接的方式還是通過(guò)Driver類來(lái)操作,比如MysqlDataSource底層的連接、知名數(shù)據(jù)庫(kù)連接池Druid的DruidAbstractDataSource的createPhysicalConnection方法。
//MysqlDataSource.java
mysqlDriver.connect(jdbcUrlToUse, props);
// DruidAbstractDataSource.java
public Connection createPhysicalConnection(String url, Properties info) throws SQLException {
Connection conn;
if (getProxyFilters().size() == 0) {
conn = getDriver().connect(url, info);
} else {
conn = new FilterChainImpl(this).connection_connect(info);
}
createCount.incrementAndGet();
return conn;
}
參考資料
https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html
https://docs.oracle.com/javase/7/docs/api/index.html?java/sql/DriverManager.html
https://dev.mysql.com/doc/connector-j/6.0/en/connector-j-usagenotes-basic.html