實現一個簡易的數據庫連接池


 

 

數據庫連接池的作用:

1. 資源重用

當多個用戶頻繁的去對數據庫進行讀寫操作時,會不間斷的創建Connection,在數據庫開始讀寫數據之前,把資源過多的分配給創建連接釋放連接上,這筆開銷得不償失.數據庫連接池的對連接Connection的資源回收機制對此做出了優化

2. 更快的系統響應速度

數據庫連接池一旦初始化,用戶獲取的Connection不再創建新的,而是從現有的容器里面取,使得直接利用成為可能,避免了數據庫連接初始化和釋放過程的時間開銷,從而縮減了系統整體響應時間

3. 新的資源分配手段

對於多應用共享同一數據庫的系統而言 ,某一應用最大可用數據庫連接數的限制,避免某一應用獨占所有數據庫資源

4. 統一的連接管理,避免數據庫連接泄漏

數據庫連接池提供連接超時設定,超時后會重試,針對用戶獲取到的不健康的Connection,同樣會重新分配新的連接,從而避免了常規數據庫連接操作中可能出現的資源泄漏

實現一個簡單的數據庫連接池

目標:

  • 要實現的數據庫連接池,統一注冊驅動(替換每一次連接數據庫都要注冊驅動的時代)
  • 用戶想對數據庫進行進一步的操作,需要在數據庫連接池中獲取連接Connection
  • 用戶對隊數據庫讀寫完畢之后, 連接池回收當前的Connection

兩個容器

數據庫連接池 = 空閑連接池 + 工作連接池

三個重要的參數

  • 最大連接數
    • 最大連接數是對Connection總數的限制 一般是((核心數 * 2) + 有效磁盤數)
  • 空閑連接數
    • 空閑連接數 表示當前的空閑連接池中的Connection的數量,我們給他規定最大值和最小值
    • 當前值 < 最大連接數 表示用戶有機會獲取連接
      • 如果 空閑連接池的size>0 直接獲取連接
      • 否則 創建一個新的Connection給用戶
    • 當前值 >= 最大連接數 Connection的創建達到了上限,用戶只能等待重試
  • 工作連接數
    • 工作連接數 表示 當前工作連接池中的Connection的數量

獲取連接經歷什么?

  1. 空閑連接池中的彈出一個Connection
  2. 把當前的Connection加入到工作連接池

連接是如何被回收的?

  1. 如果空閑連接池未滿.直接添加進去
  2. 把工作連接池中相應的連接移除
  3. 如果空閑連接池滿了.直接close()掉
  4. 把工作連接池中相應的連接移除

配置文件讀取工具類

public class propertiesUtil {

    private static Properties configObj = new Properties();

    static{
        // 使用類加載器讀取放在src下的pool.properties文件
 InputStream connectionPool = Thread.currentThread().getContextClassLoader().getResourceAsStream("pool.properties"); InputStreamReader inputStreamReader = new InputStreamReader(connectionPool); try { configObj.load(inputStreamReader); } catch (IOException e) { e.printStackTrace(); } } public static String getValue(String key){ return configObj.getProperty(key); } }

定義接口,規范我們的連接池的方法

public interface myConnectionPool  {
    /**
     * 獲取連接
     * @return
     */
    public Connection getConnection();

    /**
     * 釋放連接
     * @param connection
     */
    public void releaseConnection(Connection connection);
}

具體的實現類實現myConnectionPool接口

public class ConnectionPool implements myConnectionPool
{
    // 線程安全的兩個容器,分別存放空閑線程數和活動的線程數
    private List<Connection> freeConnection = new CopyOnWriteArrayList<>();
    private List<Connection> activeConnection = new CopyOnWriteArrayList<>();
    // 原子類 標記的是 空閑池的存放的連接數
    private AtomicInteger atomicInteger;

    public ConnectionPool() {
      
        this.atomicInteger = new AtomicInteger(0);
        // 初始化空閑連接池
        init();
    }

    // 初始空閑連接池
    public void init() {
        // 獲取連接數,給freeConnection 池添加指定數量的連接數
        for (int i = 0; i < Integer.valueOf(propertiesUtil.getValue("initConnections")); i++) {
            // 創建連接
            Connection connection = newConnection();
            if (null != connection) {
                // 添加到容器
                freeConnection.add(connection);
            }
        }
    }

    // 獲取連接
    @Override
    public synchronized Connection getConnection() {
        Connection connection=null;
        // 判斷是否達到了最大連接數--> 決定給用戶連接還是讓他等待
        if (atomicInteger.get()<Integer.valueOf(propertiesUtil.getValue("maxActiveConnetions"))){
            // 當前小於最大的連接數,直接給當前的用戶連接
            if (freeConnection.size()>0){ // 空閑線程里面有直接從空閑線程里面取
                connection  = freeConnection.remove(0);
            }else{  // 空閑線程里面沒有,直接創建一個新的連接
                connection = newConnection();
            }
            // 判斷連接是否可用
             if(isAvailable(connection)){
                 // 添加到一個活動線程里面
                 activeConnection.add(connection);
             }else{ // 如果連接不可用,遞歸
                 //  如果連接不可用的話,說明有一次newConnection()失敗了,我們得 atomicInteger.decrementAndGet(); 把newConnection()里面的原子增加去掉
                 atomicInteger.decrementAndGet();
                 connection = getConnection();
             }
        }else{
            // 等待
            try {
                wait(Integer.valueOf(propertiesUtil.getValue("connTimeOut")));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return connection;
    }

    // 釋放本次連接  ; 把本次連接從活動池 轉移到 空閑池
    @Override
    public synchronized void releaseConnection(Connection connection) {
        // 判斷連接是否可用
        if(isAvailable(connection)){ // 可用
            // 回收
            // 判斷空閑池是否滿了
            if(freeConnection.size()<Integer.valueOf(propertiesUtil.getValue("maxConnections"))){
                // 未滿
                freeConnection.add(connection);
            }else{
                // 滿了
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            // 移除出去當前的這個連接
            activeConnection.remove(connection);
            atomicInteger.decrementAndGet();
            // 現在可能有連接正在等待,既然這里釋放了,那么就喚醒全部等待的線程
            notifyAll();
        }else{ // 不可用
            throw new RuntimeException("連接回收異常");
        }
    }


    // 創建新的連接
    public Connection newConnection() {
        try {
            // 注冊驅動
            Class.forName(propertiesUtil.getValue("driverName"));
            // 獲取連接
            Connection connection = DriverManager.getConnection(
                    propertiesUtil.getValue("url"),
                    propertiesUtil.getValue("userName"),
                    propertiesUtil.getValue("password"));
            // 原子增加
            atomicInteger.addAndGet(1);
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 判斷連接是否可用
    public boolean isAvailable(Connection connection){
        try {
            if (null==connection||connection.isClosed()){
                return false;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return true;
    }
}

配置文件

# 數據庫相關
driverName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/text
userName=root
password=root

# 空閑池的 最小數
minConnections=1
# 空閑池的 最大數
maxConnections=10
# 初始化的連接數
initConnections=5

# 本次連接超時時間(重試時間)
connTimeOut=1000
# 最大的連接數
maxActiveConnetions=10

 

 

此文來源於:https://www.cnblogs.com/ZhuChangwu/p/11150572.html

 


免責聲明!

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



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