先來看看java純jdbc查詢數據的示例:
try {//加載對應的驅動類Class.forName("com.mysql.cj.jdbc.Driver");//創建連接Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC", "root", "root123");String sql = "select * from t_user";//創建statementStatement createStatement = connection.createStatement();//利用statement執行SQL語句返回結果集ResultSet rs = createStatement.executeQuery(sql);//遍歷結果集while(rs.next()) {System.out.print(rs.getString(1) + " > ");System.out.print(rs.getString(2) + " > ");System.out.print(rs.getString(3) + " > ");System.out.println(rs.getString(4));}//關閉rs.close();createStatement.close();connection.close();
} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();
} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();
}
這是一個最基礎的查詢數據的示例,也是所有的使用Java ORM框架與數據庫交互的底層,只不過是封裝一下罷了,但是像這種使用DriverManager創建連接的方式,已經基本淘汰了,在應用中是比較浪費資源的,所以JDK就提供一種數據庫連接池接口,供第三方組件實現,java.sql.DataSource,這個僅僅是個接口,具體的連接池的實現需第三方進行實現。
我們就直接先看一下Mybatis中的數據源連接池是怎么實現的。
設計模式
我們現需要了解一下數據源模塊中的設計模式
工廠模式(Factory Pattern)
是 Java 中最常用的設計模式之一。這種類型的設計模式屬于創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,并且是通過使用一個共同的接口來指向新創建的對象。
UML:
但是這種工廠模式存在一定的弊端,比如在新增一個新業務模塊的時候,是必須修改創建工廠的代碼,違反了開閉原則。
所以就有一種新澤設計模式,
抽象工廠模式(Abstract Factory Pattern)
是圍繞一個超級工廠創建其他工廠。該超級工廠又稱為其他工廠的工廠。這種類型的設計模式屬于創建型模式,它提供了一種創建對象的最佳方式。
在抽象工廠模式中,接口是負責創建一個相關對象的工廠,不需要顯式指定它們的類。每個生成的工廠都能按照工廠模式提供對象。
當業務擴展的時候新增擴展的工廠,無需修改工廠代碼,Mybatis的數據源模塊就是使用的抽象工廠設計模式。
源碼分析
在源碼中超級工廠如下:
package org.apache.ibatis.datasource;import java.util.Properties;import javax.sql.DataSource;/*** @author Clinton Begin*/
public interface DataSourceFactory {void setProperties(Properties props);DataSource getDataSource();}
設計的UML如下(一個工廠類對應只生產一種數據源):
JndiDataSourceFactory:是一個引用,可以直接獲取應用級容器中的上下文數據源。
UnpooledDataSourceFactory:生產UnpooledDataSource的數據源工廠,單一連接,非使用了數據源連接池。
PooledDataSourceFactory:生產PooledDataSource數據源工廠,提供了一個線程安全的數據源連接池。
UnpooledDataSource
雖說是繼承了DataSource但是并沒有具體的實現了連接池的特性,可以看一下這個是怎么產出Connection
跟開始那個JDBC連接數據庫的示例是一致的用法。
PooledDataSource
這個就是真正的數據源連接池的實現
連接池需要比較多的參數設置,比如超時,檢測連接是否有效,活動的連接,空閑連接等等。
所以今天就講講比較核心的一些東西:
里面創建連接是通過創建UnpooledDataSource對象來產出連接的,連接主要是存于List當中,然后配合一系列的操作就變成了線程安全的連接池了,
但是Mybatis的連接池的連接并非直接的使用的Connection而是使用的PooledConnection,進去發現這個是個連接代理,給真正的連接進行了代理增強
連接池釋放連接的過程
連接池獲取連接的過程(這個就比較長了)
這里用到了并發編程的知識,大家可以看看我之前發布的博文,有講解這一塊的東西
進行校驗后會將當前的線程添加到活動連接集合當中,
在獲取PooledConnection對象后,獲取的連接是代理的連接
解析基本結束了。
最后要提一下為什么在JDBC中使用連接只要用DriverManager.getConnection就能獲取連接了,
因為在Class.forName("")加載的時候會去加載驅動類的靜態代碼塊,將其驅動放到registeredDrivers集合中,這個是個CopyOnWriteArrayList讀寫分離集合
然后在DriverManager獲取連接