1. 程式人生 > >自定義資料結構設計JDBC連線池提高效能

自定義資料結構設計JDBC連線池提高效能

 

// 後面貼上原始碼

之前寫一個小工具,發現了一個問題,發現部署到雲端計算上面,由於需要操作其他環境的資料庫,發現獲取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);

 

本文主要給大家提供一個思路,深入理解連線池。大家可以自己自定義自己想要的資料結構模型,去獲取相應的資料庫連線池。程式碼是活的,思路是死的。