資料來源
從接觸DBMS開始就在用資料來源(DataSource),它其中很重要的一個作用就是可以管理Connection,管理的方式也就是經常聽到的ConnectionPool。它的管理其實就是對DriverManager擷取Connection進行了封裝。
下面就首先看看用DataSource來取代DriverManager來擷取Connection的好處:
一般DataSource內部會用一個串連池來緩衝Connection,這樣獲得Connection速度很快,可以大幅度提高資料庫的訪問速度;通過它獲得的Connection都是已經被包裹過的(不是驅動原來的串連),他的close方法已經被修改(並不是真正的關閉)。我們只需和DataSource打交道,不會直接存取串連池。
串連池
前面部落格講了,操作資料庫的一般步驟:
1.註冊驅動
2.建立串連
3.建立執行sql語句的對象
4.執行語句
5.處理執行結果
6.釋放資源
上面的過程其實就是用戶端與DB伺服器互動的過程。這個過程就像兩個人隔著一條河想要交流一樣,其中最費時間的莫過於屬搭橋的過程了。上面第二步“建立串連”的過程也就是搭橋的過程了。
所以,建立Connection就相當於建一座橋,是資料庫操作中最耗時的。所以用完以後就關掉是很浪費的。現在,建立完以後將它放到集合中(arrayList或linkList),用的時候從集合中取,用完了還放回集合中,這樣串連就可以複用了。就是用一個集合容器來緩衝Connection對象。
上面說的集合其實就是串連池了,串連池可以理解成一個能夠存放Connection的Collection,有兩種形式,即arrayList或linkList。arrayList實際為一個數組,訪問速度很快;linkList為一個鏈表,增、刪速度比較快。而串連池中的Connection需要頻繁的增刪,所以採用linkList來作為Connection對象的容器集合。
下面就用代碼類比一個DataSource內部的串連池:
import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.util.LinkedList;/** * @author-zhipeng */public class MyDataSource {private static String url = "jdbc:mysql://localhost:3306/jdbc";private static String user = "root";private static String password = "";private static int initCount = 5;private static int maxCount = 10;private int currentCount = 0;//建立一個LinkedList作為Connection的容器LinkedList<Connection> connectionsPool = new LinkedList<Connection>();//初始,建立5個Connection對象放到LinkedList中,用的時候從鏈表頭部取,不用了放到尾部public MyDataSource() {try {for (int i = 0; i < initCount; i++) {this.connectionsPool.addLast(this.createConnection());this.currentCount++;}} catch (SQLException e) {throw new ExceptionInInitializerError(e);}}//建立串連時就調用這個方法--從Connection鏈表容器頭部取一個public Connection getConnection() throws SQLException {//枷鎖-針對並行作業synchronized (connectionsPool) {//如果串連池(實際為LinkList)中還有Connection對象則取出一個if (this.connectionsPool.size() > 0)return this.connectionsPool.removeFirst();//如果串連池沒有(初始為5個)Connection對象,而請求串連數小於最大串連數,則建立一個新的Connectionif (this.currentCount < maxCount) {this.currentCount++;return this.createConnection();}//否則拋出異常,超過最大串連數,沒有串連可用throw new SQLException("已沒有連結");}}//關閉串連時就調用這個方法--不是真正的釋放串連,而是放到從Connection鏈表容器的尾部public void free(Connection conn) {this.connectionsPool.addLast(conn);}//建立Connection的根代碼private Connection createConnection() throws SQLException {return DriverManager.getConnection(url, user, password);}}
從上面的代碼實現可知,如果超過Connection Pool的最大串連數(10個)則必然會因沒有串連可以使用而拋異常,下面就用代碼實驗一下:
/** * @author-zhipeng */public class TestConnectionPool {private static DataSource myDataSource = null;/** * 迴圈建立11個Connection,期間都不釋放(關閉) */public static void main(String[] args) throws Exception {for (int i = 0; i < 11; i++) {Connection conn = myDataSource.getConnection();System.out.println(conn);//JdbcUtils.free(null, null, conn);}}}
然後運行,就會發現,當建立第11個的時候就會拋出異常:
這也驗證了我們上面的實現。當然還可以進行一系列其它的測試,比如建立五個再釋放一個,然後再建立一個,這是你就會發現,Connection Pool的“隊列”結構。
總結
上面簡單介紹了DataSource,和Connection Pool,並用代碼簡單類比了它的原理。這也是對舊知識的溫習和加深理解的過程吧。