自定義一個簡單的JDBC連接池

来源:http://www.cnblogs.com/samluby/archive/2017/12/19/8068277.html
-Advertisement-
Play Games

一、什麼是JDBC連接池? 在傳統的JDBC連接中,每次獲得一個Connection連接都需要載入通過一些繁雜的代碼去獲取,例如以下代碼: 這樣繁雜的操作只為了獲取一次連接,當然,我們可以將其封裝成一個工具類來訪問(上圖以封裝好Connection的連接),但是每一次連接都需要取載入一次是不是很浪費 ...


一、什麼是JDBC連接池?

      在傳統的JDBC連接中,每次獲得一個Connection連接都需要載入通過一些繁雜的代碼去獲取,例如以下代碼:

public static Connection getConn(){
        Connection conn = null;
        String url = "jdbc:mysql://localhost:3306/test";
        String user = "root";
        String password = "root";
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

這樣繁雜的操作只為了獲取一次連接,當然,我們可以將其封裝成一個工具類來訪問(上圖以封裝好Connection的連接),但是每一次連接都需要取載入一次是不是很浪費性能,為了優化性能,那麼就出現了連接池。

   連接池在初始化的時候就創建了幾個連接供我們使用,當我們需要連接時只需要從連接池中獲取已存在的連接,當初始化的幾個連接都沒有時,會重新創建一個連接,使用完連接後不會去銷毀連接,而是歸還給連接池供後面需要連接的使用。(當然,連接池不僅僅只是這麼簡單,這裡就只做這些介紹)

  常用的連接池有DBCP、C3P0,現在最主流是好像是阿裡的Druid連接池,還有tomcat的自帶的JNDI連接池

 

二、自定義一個簡單的連接池

    對自定義連接池的分析:

                                        1.2.因為是連接池 ,我們需要實現DataSource介面,並實現其中的方法,基於我們的情況,我們關於與getConnection()方法;

                                        2.既然要存放幾個連接對象,那麼我們用一個集合來存放它,基於會經常操作增加和刪除那麼選用LinkedList;

                                        3.連接的銷毀並不是銷毀連接,而是將連接歸還給連接池

  編碼:

  1.創建一個類MyDataSource 並實現DataSource介面

     當此類載入時它就需要有一個容器來存放Connection,所以定義一個靜態的屬性:

private static List<Connection> connectionList = new LinkedList<>();

 2.因為需要取獲得資料庫連接,所以我們封裝一個獲取資料庫連接的方法

public Connection getOneConnection(){
        Connection conn = null;
        try{
//此處通過外部的properties文件來獲取的數據,這樣更加靈活。 InputStream in
= MyDataSource.class.getClassLoader(). getResourceAsStream("jdbc/jdbc.properties"); Properties pro = new Properties(); pro.load(in); driver = pro.getProperty("driver"); url = pro.getProperty("url"); username = pro.getProperty("user"); password = pro.getProperty("password"); Class.forName(driver); conn = DriverManager.getConnection(url,username,password); }catch (Exception e){ e.getStackTrace(); } return conn; }

註意的是我這裡通過propertie文件的獲取的數據,可根據實際情況來選擇

  3.初始化幾個連接放入容器中。可以使用靜態代碼塊來實現,但是如果沒有使用此數據源那麼就造成了資源的浪費,所以我考慮將初始化幾個連接的實現放到他的構造方法中,即當需要此連接池的時候他才會隨之創建幾個連接。如下:

public MyDataSource() {
        for (int i = 0; i < 5; i++) {
            Connection conn = getOneConnection();//調用創建連接的方法
            connectionList.add(conn);
        }
    }

4.現在開始重寫外部從此連接池中獲取連接的方法getConnection()

@Override
    public Connection getConnection() throws SQLException {
        Connection conn = null;
        if(connectionList == null || connectionList.size() <= 0){
            Connection connection = getConnection();
            connectionList.add(connection);
        }
        conn = connectionList.remove(0);
        return conn;
    }

5.創建一個對象返回的方法,即將用完的連接放入歸還到連接池中

public void backConnection(Connection conn){
        connectionList.add(conn);
    }
    

 

OK,這樣就完成了一個簡單的自定義連接池,測試代碼如下:

 public static void main( String[] args ) throws SQLException
    {
        MyDataSource dataSource = new MyDataSource();
        Connection conn = dataSource.getConnection();
        String sql = "select * from user where u_id = ?";
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            ps.setInt(1, 1);
            rs = ps.executeQuery();
            while (rs.next()) {
                System.out.println("id="+rs.getInt(1));
                System.out.println("username="+rs.getString(2));
                System.out.println("password="+rs.getString(3));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            dataSource.backConnection(conn);
        }
    }

因為忽略,我的代碼中沒有關閉其他兩個對象。

 

現在有一個小問題就是,我們的關閉連接是通過連接池的方法來實現的,但是,如果用戶調用Connection對象的close方法,那麼連接時被銷毀了,並沒有返回給連接池,那麼我們來優化它,讓用戶使用close()方法不會去銷毀連接,而是去歸還連接。

方案有很多中,這裡採用裝飾著模式的一種。

優化:

  1.新建一個類MyConnection來實現Connection介面,其中他有屬性類型為Connection conn和一個Liis<Connection>。

private Connection conn;
    private List<Connection> pool;
    
    public MyConnection(Connection conn, List<Connection> pool) {
        this.conn = conn;
        this.pool = pool;
    }

 2.然後實現介面的close方法

    @Override
    public void close() throws SQLException {
        System.out.println("回收連接");
        pool.add(conn);
    }

 3.然後實現他獲取Statement的方法,如果不實現那麼獲取此Statement會出現空指針錯誤,我這裡就只實現了PreparedStatement的獲取方法

@Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        System.out.println("獲得Statement");
        return conn.prepareStatement(sql);
    }

4.然後刪除掉MyDataSource類中歸還連接的方法backConnection,並將構造方法和獲取連接的方法做如下改造

public MyDataSource2() {
        for (int i = 0; i < 5; i++) {
            Connection conn = getOneConnection();
            MyConnection myConn = new MyConnection(conn, connectionList);
            connectionList.add(myConn);
        }
    }
@Override
    public Connection getConnection() throws SQLException {
        Connection conn = null;
        if(connectionList == null || connectionList.size() <= 0){
            Connection connection = getConnection();
            MyConnection myConn = new MyConnection(connection, connectionList);
            connectionList.add(myConn);
        }
        conn = connectionList.remove(0);
        return conn;
    }
    

好了,這樣用戶直接調用我們的Connection的close方法就不會去銷毀連接了,會正確的歸還給了連接池了,對測試代碼稍做修改即可測試。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Java開發環境概述 1、JDK:Java開發工具包(Java Development Kit),包括java編譯器、java運行時環境和常用的類庫 2、JRE:Java運行時環境(Java Runtime Environment) 二、跨平臺特性 1、平臺指的是操作系統(Windows,Lin ...
  • 編者按:README:此代碼為用戶登陸界面,添加了尋求幫助選項。1.學習了基本數據類型,string, int,以及while迴圈,continue, break, if, elif, else條件語句,“x".format(x)變數替代2.上網搜的dictionary用法,由於用的是python3 ...
  • 學而不思則罔,思而不學則殆。 mybatis 增刪改查,用到了MyEclipse中自帶的Junit4做單元測試,沒啥難度,作為練習。關於jar包和目錄結構請參考上一篇,這裡直接上代碼。 下一篇會寫關於配置文件優化,聯合查詢,以及使用註解的方式,客官們不要著急! ...
  • IO位元組輸入輸出流 OutputStream:位元組輸出流 該抽象類是所有位元組輸出流的超類; 定義了一些共性的成員方法: 1.寫入一個位元組 2.寫入位元組數組 3.寫入位元組數組的一部分 4.刷新輸出流,並強制寫出所有緩衝的輸出位元組 5.關閉輸出流並釋放與之有關的所有系統資源 FileOutputStre ...
  • python 介紹 一、簡介 Python(英國發音:/ˈpaɪθən/ 美國發音:/ˈpaɪθɑːn/),是一種廣泛使用的高級編程語言,屬於通用型編程語言,由Guido van Rossum 創造,第一版發佈於 1991 年。作為一種解釋型語言,Python 的設計哲學強調代碼的可讀性和簡潔的語法 ...
  • 第一種:利用eclipse中自帶的export功能 第一種方法分兩種情況先來看第一種情況:沒有引用外部jar的項目打包 步驟一:右鍵點擊項目選擇導出(export),選擇java>jar文件(不是選擇可運行jar文件) 步驟二:選擇你要導出的項目以及文件,指定文件導出路徑。連續點擊兩個下一步後到第四 ...
  • 外觀(Facade)模式 當使用子系統的代碼時,你也許會發現自己過於深入地調用子系統的邏輯代碼。如果子系統代碼總是在不斷變化,而你的代碼卻又在許多不同地方與子系統代碼交互,那麼隨著子系統的發展,你也許會發現維護代碼變得非常困難。 在項目中集成複雜的第三方代碼,或在系統中逐漸形成大量僅在系統自身內部有 ...
  • 客戶端緩存的機制:Eureka還提供了客戶端緩存的機制,即使所有的Eureka Server都掛掉,客戶端仍可以利用緩存中的信息調用服務節點的服務。Eureka一般配合Ribbon進行使用,Ribbon提供了客戶端負載均衡的功能,Ribbon利用從Eureka中讀取到的服務信息,在調用服務節點提供的... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...