JDBC 數據庫連接池


數據庫連接池原理-傳統方式

當有多個線程,每個線程都需要連接數據庫執行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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM