數據庫連接池的作用:
1. 資源重用
當多個用戶頻繁的去對數據庫進行讀寫操作時,會不間斷的創建Connection,在數據庫開始讀寫數據之前,把資源過多的分配給創建連接釋放連接上,這筆開銷得不償失.數據庫連接池的對連接Connection的資源回收機制對此做出了優化
2. 更快的系統響應速度
數據庫連接池一旦初始化,用戶獲取的Connection不再創建新的,而是從現有的容器里面取,使得直接利用成為可能,避免了數據庫連接初始化和釋放過程的時間開銷,從而縮減了系統整體響應時間。
3. 新的資源分配手段
對於多應用共享同一數據庫的系統而言 ,某一應用最大可用數據庫連接數的限制,避免某一應用獨占所有數據庫資源。
4. 統一的連接管理,避免數據庫連接泄漏
數據庫連接池提供連接超時設定,超時后會重試,針對用戶獲取到的不健康的Connection,同樣會重新分配新的連接,從而避免了常規數據庫連接操作中可能出現的資源泄漏
實現一個簡單的數據庫連接池
目標:
- 要實現的數據庫連接池,統一注冊驅動(替換每一次連接數據庫都要注冊驅動的時代)
- 用戶想對數據庫進行進一步的操作,需要在數據庫連接池中獲取連接Connection
- 用戶對隊數據庫讀寫完畢之后, 連接池回收當前的Connection
兩個容器
數據庫連接池 = 空閑連接池 + 工作連接池
三個重要的參數
- 最大連接數
- 最大連接數是對Connection總數的限制 一般是((核心數 * 2) + 有效磁盤數)
- 空閑連接數
- 空閑連接數 表示當前的空閑連接池中的Connection的數量,我們給他規定最大值和最小值
- 當前值 < 最大連接數 表示用戶有機會獲取連接
- 如果 空閑連接池的size>0 直接獲取連接
- 否則 創建一個新的Connection給用戶
- 當前值 >= 最大連接數 Connection的創建達到了上限,用戶只能等待重試
- 工作連接數
- 工作連接數 表示 當前工作連接池中的Connection的數量
獲取連接經歷什么?
- 空閑連接池中的彈出一個Connection
- 把當前的Connection加入到工作連接池
連接是如何被回收的?
- 如果空閑連接池未滿.直接添加進去
- 把工作連接池中相應的連接移除
- 如果空閑連接池滿了.直接close()掉
- 把工作連接池中相應的連接移除
配置文件讀取工具類
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