自定義數據庫連接池

一、自定義數據庫連接池實現思想

依賴的jar
依賴的jar包
1沟蔑、思想步驟
  • 1湿诊、鏈接池類
  • 2、制定全局參數瘦材,初始化數目厅须,最大連接數,當前連接食棕,鏈接池集合
  • 3朗和、構造函數循環(huán)創(chuàng)建3個鏈接
  • 4、寫一個從創(chuàng)建連接的方法
  • 5簿晓、獲取連接
    判斷有鏈接直接拿
    是否達到最大連接數眶拉,達到拋出異常
    沒達到創(chuàng)建新連接
  • 6、釋放鏈接 放回集合中
  • 7抢蚀、優(yōu)化連接 擴展close()方法 動態(tài)代理
2镀层、思想原理圖
原理圖
3、優(yōu)化:

當關閉連接時候把鏈接放入連接池 就是調用clos()方法觸發(fā)releaseConnection(Connection conn)方法
*解決1:繼承Connection重寫clos方法 方法太多不可行
*解決2:動態(tài)代理
如果對某個接口中得到某個方法進行擴展,而不想實現接口所有的方法可以使用的動態(tài)代理模式
java中代理模塊:靜態(tài)唱逢,動態(tài)吴侦,cglib代理
動態(tài)代理可以及檢測接口中方法的執(zhí)行
如何生成動態(tài)代理 jdk API提供Proxy

 static Object newProxyInstance{
     ClassLoader loader //當前使用的類加載器
     Class<?>interface //目標對象Connection實現的接口類型
     InvocationHabdler h //事件處理器,當執(zhí)行上面接口中的方法的時候坞古,  就自動觸發(fā)處理器方法备韧,把當前執(zhí)行的發(fā)方法(method)作為參數傳入
}

二、代碼實現

1痪枫、定義獲取連接的接口DataSource.java
package work.doudou.MyPool;

import java.sql.Connection;
//定義獲取連接的接口
public interface DataSource {
    public Connection getConnection();
}
2织堂、數據源BasicDataSource.java
package work.doudou.MyPool;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;


/**
 * 自定義鏈接池
 * 1、MyPool.java類奶陈,鏈接池類
 * 2易阳、制定全局參數,初始化數目吃粒,最大連接數潦俺,當前連接,鏈接池集合
 * 3徐勃、構造函數循環(huán)創(chuàng)建3個鏈接
 * 4事示、寫一個從創(chuàng)建連接的方法
 * 5、獲取連接    
 *      判斷有鏈接直接拿
 *      是否達到最大連接數僻肖,達到拋出異常 
 *      沒達到創(chuàng)建新連接
 * 6肖爵、釋放鏈接   放回集合中
 * 7、優(yōu)化連接   擴展close()方法    動態(tài)代理
 **/

/* 優(yōu)化:
 * 當關閉連接時候把鏈接放入連接池     就是調用clos()方法觸發(fā)releaseConnection(Connection conn)方法
 *      解決1:繼承Connection重寫clos方法   方法太多不可行
 *      解決2:動態(tài)代理
 *          如果對某個接口中得到某個方法進行擴展臀脏,而不想實現接口所有的方法可以使用的動態(tài)代理模式
 *          java中代理模塊:靜態(tài)劝堪,動態(tài),cglib代理
 *          動態(tài)代理可以及檢測接口中方法的執(zhí)行
 *      如何生成動態(tài)代理 jdk API提供Proxy
 *          static Object newProxyInstance{
 *              ClassLoader loader 當前使用的類加載器
 *              Class<?>interface 目標對象Connection實現的接口類型
 *              InvocationHabdler h 事件處理器揉稚,當執(zhí)行上面接口中的方法的時候幅聘,就自動觸發(fā)
 *                                  處理器方法,把當前執(zhí)行的發(fā)方法(method)作為參數傳入
 *          }
 */
public class BasicDataSource implements DataSource{
    //數據庫連接賬號
    private String username=null;
    //數據庫連接密碼
    private String password=null;
    //驅動com.mysql.jdbc.Driver
    private String driver=null;
    //數據庫連接url  jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8","root","root
    private String url=null;
    //初始化數目
    private int init_count=3;
    //最大連接數
    private int max_count=5;
    //連接池里頭的連接
    private int current_count=0;
    //連接池窃植,存放鏈接
    private LinkedList<Connection> connections=new LinkedList<Connection>();
    
    
    //1、初始化連接放入連接池  
    private void createBasicDataSource(){
    //初始化連接
        for(int i=0;i<init_count;i++){
            //記錄當前連接數
            current_count++;
            //把鏈接放入連接池
            connections.addLast(createConnection());
        }
    }
    
    //2荐糜、建新連接的方法
    private Connection createConnection(){
        try {
            Class.forName(driver);
            //原始的目標對象
            final Connection conn= DriverManager.getConnection(url,username,password);
            /*******創(chuàng)建代理對象********/
            //創(chuàng)建代理對象
            Connection proxyConnection=(Connection)Proxy.newProxyInstance(
                    //類加載器
                    conn.getClass().getClassLoader(), 
                    //目標接口對象
                    new Class[] {Connection.class},
                    //當調用conn對象的時候自動觸發(fā)事務處理器
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //方法返回值
                            Object result=null;
                            //當前執(zhí)行的方法名
                            String methoName=method.getName();  
                            //判斷執(zhí)行close()就把連接放入連接池
                            if ("close".equals(methoName)) {
                                //連接放入連接池
                                if(connections.size()<init_count){
                                    connections.addLast(conn);
                                }else{
                                //如果連接池滿了就關了連接
                                    try {
                                        current_count--;
                                        conn.close();
                                    } catch (SQLException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                }   
                            }else{
                                //調用目標方法對象
                                result=method.invoke(conn, args);
                            }
                            
                            return result;
                        }
                    }); 
            return proxyConnection;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    //3巷怜、獲取連接
    @Override
    public Connection getConnection() {
        //獲取連接之前判斷是否初始化
        if (connections.size()<=0) {
            createBasicDataSource();
        }
        //判斷是否連接,有就去出暴氏,延塑,就直拿
        if (connections.size()>0) {
            return connections.removeFirst();
        }
        //判斷連接池有沒有連接,如果沒有達到最大連接答渔,就創(chuàng)建
        if (current_count<max_count) {
            //記錄當前連接使用數
            current_count++;
            //創(chuàng)建連接
            return createConnection();
        }
        //如果已達到最大連接數就关带,就拋出異常
        throw new RuntimeException("當前連接已達到最大連接數目!");
    }
    //4、釋放鏈接
    public void releaseConnection(Connection conn) {
        //判斷當前連接池數目如果少于初始化就放入池中
        if(connections.size()<init_count){
            connections.addLast(conn);
        }else{
        //如果連接池滿了就關了連接
            try {
                current_count--;
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getInit_count() {
        return init_count;
    }

    public void setInit_count(int init_count) {
        this.init_count = init_count;
    }

    public int getMax_count() {
        return max_count;
    }

    public void setMax_count(int max_count) {
        this.max_count = max_count;
    }

    public int getCurrent_count() {
        return current_count;
    }

    public LinkedList<Connection> getConnections() {
        return connections;
    }   
}

3宋雏、測試類test.java
package work.doudou.MyPool;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class test {
    //創(chuàng)建數據庫連接池基礎數據源的對象
    static BasicDataSource pool=new BasicDataSource();
    //設置基礎數據
    static{
        pool.setUsername("root");
        pool.setPassword("root");
        pool.setDriver("com.mysql.jdbc.Driver");
        pool.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8");
        pool.setInit_count(5);
        pool.setMax_count(7);
    }
    //返回連接池對象
    public static DataSource getDataSource() {
        return pool;
    }
    
    //測試主方法
    public static void main(String[] args) {    
        //獲取數據庫連接
        Connection connection=getDataSource().getConnection();
        //查詢執(zhí)行器
        Statement s=null;
        //返回結果集
        ResultSet rs=null;
        //控制臺輸出獲取到連接的地址
        System.out.println(connection);
        try {
            //執(zhí)行查詢
            s=connection.createStatement();
            rs=s.executeQuery("select * from a");
            while (rs.next()) {
                System.out.println(rs.getInt("a"));
                
            }
            //關閉結果集
            rs.close();
            //關閉執(zhí)行器
            s.close();
            //這里關閉連接是吧連接放回連接池
            connection.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("總共的連接數目"+pool.getCurrent_count());
        System.out.println("連接池里空閑的連接"+pool.getConnections().size());
  } 
}

三芜飘、運行結果

運行結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市磨总,隨后出現的幾起案子嗦明,更是在濱河造成了極大的恐慌,老刑警劉巖蚪燕,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娶牌,死亡現場離奇詭異,居然都是意外死亡馆纳,警方通過查閱死者的電腦和手機诗良,發(fā)現死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲁驶,“玉大人鉴裹,你說我怎么就攤上這事×橄樱” “怎么了壹罚?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長寿羞。 經常有香客問我猖凛,道長,這世上最難降的妖魔是什么绪穆? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任辨泳,我火速辦了婚禮,結果婚禮上玖院,老公的妹妹穿的比我還像新娘菠红。我一直安慰自己,他們只是感情好难菌,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布试溯。 她就那樣靜靜地躺著,像睡著了一般郊酒。 火紅的嫁衣襯著肌膚如雪遇绞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天燎窘,我揣著相機與錄音摹闽,去河邊找鬼。 笑死褐健,一個胖子當著我的面吹牛付鹿,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼舵匾,長吁一口氣:“原來是場噩夢啊……” “哼俊抵!你這毒婦竟也來了?” 一聲冷哼從身側響起纽匙,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤务蝠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后烛缔,有當地人在樹林里發(fā)現了一具尸體馏段,經...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年践瓷,在試婚紗的時候發(fā)現自己被綠了院喜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡晕翠,死狀恐怖喷舀,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情淋肾,我是刑警寧澤硫麻,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站樊卓,受9級特大地震影響拿愧,放射性物質發(fā)生泄漏。R本人自食惡果不足惜碌尔,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一浇辜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唾戚,春花似錦柳洋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至募书,卻和暖如春轧钓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锐膜。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留弛房,地道東北人道盏。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荷逞。 傳聞我的和親對象是個殘疾皇子媒咳,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內容