資料庫連接池原理-傳統方式 當有多個線程,每個線程都需要連接資料庫執行SQL語句的話,那麼每個線程都會創建一個連接,並且在使用完畢後,關閉連接。創建連接和關閉連接的過程也是比較消耗時間的,當多線程併發的時候,系統就會變得很卡頓。同時,一個資料庫同時支持的連接總數也是有限的,如果多線程併發量很大,那麼 ...
資料庫連接池原理-傳統方式
當有多個線程,每個線程都需要連接資料庫執行SQL語句的話,那麼每個線程都會創建一個連接,並且在使用完畢後,關閉連接。
創建連接和關閉連接的過程也是比較消耗時間的,當多線程併發的時候,系統就會變得很卡頓。
同時,一個資料庫同時支持的連接總數也是有限的,如果多線程併發量很大,那麼資料庫連接的總數就會被消耗光,後續線程發起的資料庫連接就會失敗。
資料庫連接池原理-使用池
與傳統方式不同,連接池在使用之前,就會創建好一定數量的連接。
如果有任何線程需要使用連接,那麼就從連接池裡面借用,而不是自己重新創建.
使用完畢後,又把這個連接歸還給連接池供下一次或者其他線程使用。
倘若發生多線程併發情況,連接池裡的連接被借用光了,那麼其他線程就會臨時等待,直到有連接被歸還回來,再繼續使用。
整個過程,這些連接都不會被關閉,而是不斷的被迴圈使用,從而節約了啟動和關閉連接的時間。
ConnectionPool構造方法和初始化
1. ConnectionPool() 構造方法約定了這個連接池一共有多少連接。2. 在init() 初始化方法中,創建了size條連接。 註意,這裡不能使用try-with-resource這種自動關閉連接的方式。 因為連接恰恰需要保持不關閉狀態,供後續迴圈使用。
3. getConnection, 判斷是否為空,如果是空的就wait等待,否則就借用一條連接出去。
4. returnConnection, 在使用完畢後,歸還這個連接到連接池,並且在歸還完畢後,調用notifyAll,通知那些等待的線程,有新的連接可以借用了。
註:連接池設計用到了多線程的wait和notifyAll
public class ConnectionPool { List<Connection> cs = new ArrayList<Connection>(); int size; //定義連接池裡的最大連接數 public ConnectionPool(int size){ this.size = size; init(); } public void init(){ //這裡恰恰不能使用try-with-resource的方式, // 因為這些連接都需要是活的,不要被自動關閉 try{ Class.forName("com.mysql.jdbc.Driver"); for (int i = 0;i<size;i++){ Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "123456"); cs.add(c); } }catch (ClassNotFoundException e){ e.printStackTrace(); }catch (SQLException e){ e.printStackTrace(); } } //需要連接時,將連接分配出去的方法 public synchronized Connection getConnection(){ while(cs.isEmpty()){ try{ this.wait();//this表示引用該函數所屬類的當前對象 }catch (InterruptedException e) { e.printStackTrace(); } } Connection c = cs.remove(0); return c; } //用完連接後,將連接還給連接池的方法 public synchronized void returnConnection(Connection c){ cs.add(c); this.notifyAll(); } }
測試類
首先初始化一個有3條連接的資料庫連接池然後創建100個線程,每個線程都會從連接池中借用連接,並且在借用之後,歸還連接。 拿到連接之後,執行一個耗時1秒的SQL語句。public class TestConnectionPool { public static void main(String[] args) { ConnectionPool cp = new ConnectionPool(3); for (int i = 0;i<100;i++){ new WorkingThread("working thread"+i,cp).start(); } } } class WorkingThread extends Thread{ private ConnectionPool cp; public WorkingThread(String name,ConnectionPool cp){ super(name);//給當前thread命名 this.cp = cp; } public void run(){ Connection c = cp.getConnection(); System.out.println(this.getName()+":\t 獲取了一根連接,並開始工作"); try(Statement st = c.createStatement()){ //模擬時耗1秒的資料庫SQL語句 Thread.sleep(1000); st.execute("select * from hero"); }catch (SQLException | InterruptedException e){ e.printStackTrace(); } cp.returnConnection(c); } }
運行程式,就可以觀察到如圖所示的效果
原文鏈接:http://how2j.cn/k/jdbc/jdbc-connection-pool/610.html