自定義資料結構設計JDBC連線池提高效能
阿新 • • 發佈:2018-11-12
// 後面貼上原始碼
之前寫一個小工具,發現了一個問題,發現部署到雲端計算上面,由於需要操作其他環境的資料庫,發現獲取66 175環境的獲取連線非常緩慢。
通過列印日誌,然後部署到伺服器,發現獲取175環境的資料庫連線池居然要6s?? 獲取66環境需要3s 顯然不合理?
一個查詢居然要5-6秒,具體原因我真的不懂,為啥175連的那麼困難? 是不是物理機隔得太遠了?還是啥。。 反正想著既然這樣,
本來想用業界成熟的c3p0,或者本平臺已經在使用的阿里巴巴druid連線池,但是好像不太符合我們的需求。因為我們需要儲存很多個不同環境的連線,資料結構不能是List單純儲存連線,需要一個map對映。
最後自己寫一個自定義連線池吧。。。 把獲取到的連線儲存到集合裡,不需要就放回去,需要在拿回來,這是最簡單的思路,就開始編碼了,看看能不能解決問題。
思路大概這樣吧:
注意要給釋放連線和獲取連線加上重入鎖,保證多執行緒的可靠性。
最後從新部署測試。
----------遺留問題,一直不明白為什麼jdbc建立connection連線 對於66環境和175環境需要3-5s, 而其他環境建立連線就算不用連線池只需要幾ms。
最後附上程式碼
package com.huawei.solution.utils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import static com.huawei.solution.constants.CommonConstants.PASS_WORD; import static com.huawei.solution.constants.CommonConstants.USER_NAME; import static com.huawei.solution.constants.CommonConstants.DRIVER_CLASS_NAME; /** * @ClassNme DataSourcePoolNew * @Author x84104122 * @Date 2018/10/29 17:45 * @Description 自定義簡單資料庫對映連線池 */ public class DataSourcePoolNew { /** * 最大連線數 */ private static final int COUNT = 10; /** * 存放資料庫 * key 為環境 value 為資料庫 */ public static final Map<Integer, LinkedList<Connection>> connections = new ConcurrentHashMap<>(); /** * 建立鎖 */ private static final ReentrantLock lock = new ReentrantLock(); private static final Condition notEmpty = lock.newCondition(); private static final Condition notFull = lock.newCondition(); /** * 資料庫連線 */ private static String URL; public DataSourcePoolNew() { } /** * 初始化資訊 */ public DataSourcePoolNew(Integer key,String url) { final ReentrantLock reentrantLock = lock; reentrantLock.lock(); try { //載入驅動 URL = url; Class.forName(DRIVER_CLASS_NAME); LinkedList<Connection> connectionList = new LinkedList<>(); for (int i = 0; i < COUNT; i++) { Connection connection = DriverManager.getConnection(URL, USER_NAME, PASS_WORD); connectionList.add(connection); } connections.put(key, connectionList); } catch (Exception e) { e.printStackTrace(); } finally { reentrantLock.unlock(); } } /** * 獲取Connection */ public Connection getConnection(Integer key) { if (!connections.containsKey(key)){ return null; } final ReentrantLock reentrantLock = lock; reentrantLock.lock(); try { //如果沒有連線了,則等待著新放入的連線 if (connections.get(key).isEmpty()) { notEmpty.await(); } Connection connection = connections.get(key).removeFirst(); notFull.signalAll(); return connection; } catch (InterruptedException e) { e.printStackTrace(); } finally { reentrantLock.unlock(); } return null; } /** * 釋放連線 * * @param connection */ public static void release(Integer key, Connection connection) { if (!connections.containsKey(key)){ return ; } final ReentrantLock reentrantLock = lock; reentrantLock.lock(); try { if (connections.get(key).size() == COUNT) { notFull.await(); } if (connection == null || connection.isClosed()) { connections.get(key).add(DriverManager.getConnection(URL, USER_NAME, PASS_WORD)); notEmpty.signalAll(); return; } //恢復預設值 if (connection.getAutoCommit() == false) { connection.setAutoCommit(true); } connections.get(key).add(connection); notEmpty.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { reentrantLock.unlock(); } } }
使用Demo
獲取連線
if (DataSourcePoolNew.connections.containsKey(environment) && !DataSourcePoolNew.connections.get(environment).isEmpty()) { con = DataSourcePoolNew.connections.get(environment).removeFirst(); } else { con = new DataSourcePoolNew(environment, url).getConnection(environment); }
釋放連線
放回集合了
DataSourcePoolNew.release(environment, con);
本文主要給大家提供一個思路,深入理解連線池。大家可以自己自定義自己想要的資料結構模型,去獲取相應的資料庫連線池。程式碼是活的,思路是死的。