連接池的作用就是爲了提高性能,既然能提高性能還等啥,我們自己模擬編寫一個連接池,探其究竟,明其原理。

連接池的作用就是爲了提高性能。

連接池的作用:連接池是將已經創建好的連接保存在池中,當有請求來時,直接使用已經創建好的連接對數據庫進行訪問。這樣省略了創建連接和銷燬連接的過程。這樣性能上得到了提高。

基本原理是這樣的:

  1. 建立數據庫連接池對象(服務器啓動)。
  2. 按照事先指定的參數創建初始數量的數據庫連接(即:空閒連接數)。
  3. 對於一個數據庫訪問請求,直接從連接池中得到一個連接。如果數據庫連接池對象中沒有空閒的連接,且連接數沒有達到最大(即:最大活躍連接數),創建一個新的數據庫連接。
  4. 存取數據庫。
  5. 關閉數據庫,釋放所有數據庫連接(此時的關閉數據庫連接,並非真正關閉,而是將其放入空閒隊列中。如實際空閒連接數大於初始空閒連接數則釋放連接)。
  6. 釋放數據庫連接池對象(服務器停止、維護期間,釋放數據庫連接池對象,並釋放所有連接)。

連接池的概念和爲什麼要使用連接池?

連接池放了N個Connection對象,本質上放在內存當中,在內存中劃出一塊緩存對象,應用程序每次從池裏獲得Connection對象,而不是直接從數據裏獲得,這樣不佔用服務器的內存資源。

如果不使用連接池會出現的情況:

  • 佔用服務器的內存資源
  • 導致服務器的速度非常慢

 既然,大家都瞭解了連接池的好處,那麼我就動手寫個固定大小的連接池,以方便夥伴們學習和交流。話不多說,直接上代碼,走着~

package com.smallfan.connectionpool;

import com.smallfan.TestVisiblity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * @PACKAGE_NAME: com.smallfan.connectionpool
 * @NAME: ConnectionPool
 * @USER: dell
 * @DATE: 2020/5/28
 * @PROJECT_NAME: aboutthread
 * 模擬實現固定大小的數據庫連接池
 */
public class TestPool{
    public static void main(String[] args) {
        //初始化連接池
        ConnectionPool pool = new ConnectionPool(2);

        for (int i = 0; i < 5; i++) {//創建5個線程爭搶連接池
            new Thread(()->{
                Connection apply = pool.apply();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                pool.free(apply);
            }).start();
        }
    }
}
class ConnectionPool {
    static Logger logger = LoggerFactory.getLogger(ConnectionPool.class);
    //初始化連接池池大小
    private final int poolSize;
    //使用數組存儲連接對象
    private Connection[] connections;
    //使用原子數組記錄連接池狀態 0:空閒 1:繁忙
    private AtomicIntegerArray status;
    //初始化
    public ConnectionPool(int poolSize) {
        this.poolSize = poolSize;
        this.connections = new Connection[poolSize];
        this.status = new AtomicIntegerArray(new int[poolSize]);
        for (int i = 0; i < poolSize; i++) {//初始化數據庫連接
            connections[i] = new TestConnection("連接"+i);
        }
    }
    //申請連接
    public Connection apply(){
        while (true){
            for (int i = 0; i < poolSize; i++) {
                if(status.get(i) == 0){//是否存在空閒的連接
                    if(status.compareAndSet(i,0,1)){//更新空閒連接爲繁忙狀態,保證原子操作並返回true
                        logger.info("獲取連接 {}",connections[i]);
                        return connections[i];
                    }
                }
            }
            //若都是繁忙狀態,阻塞
            synchronized (this){
                try {
                    logger.info("等待連接");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //釋放連接
    public void free(Connection connection){
        for (int i = 0; i < poolSize; i++) {
            if (connections[i] == connection){
                logger.info("釋放連接{}",connections[i]);
                status.set(i,0);
                synchronized (this){
                    this.notifyAll();
                }
                break;
            }
        }
    }

}
//模擬實現Connection接口
class TestConnection implements Connection{

    String name;

    public TestConnection(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "TestConnection{" +
                "name='" + name + '\'' +
                '}';
    }

    public Statement createStatement() throws SQLException {
        return null;
    }

    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return null;
    }

    public CallableStatement prepareCall(String sql) throws SQLException {
        return null;
    }

    public String nativeSQL(String sql) throws SQLException {
        return null;
    }

    public void setAutoCommit(boolean autoCommit) throws SQLException {

    }

    public boolean getAutoCommit() throws SQLException {
        return false;
    }

    public void commit() throws SQLException {

    }

    public void rollback() throws SQLException {

    }

    public void close() throws SQLException {

    }

    public boolean isClosed() throws SQLException {
        return false;
    }

    public DatabaseMetaData getMetaData() throws SQLException {
        return null;
    }

    public void setReadOnly(boolean readOnly) throws SQLException {

    }

    public boolean isReadOnly() throws SQLException {
        return false;
    }

    public void setCatalog(String catalog) throws SQLException {

    }

    public String getCatalog() throws SQLException {
        return null;
    }

    public void setTransactionIsolation(int level) throws SQLException {

    }

    public int getTransactionIsolation() throws SQLException {
        return 0;
    }

    public SQLWarning getWarnings() throws SQLException {
        return null;
    }

    public void clearWarnings() throws SQLException {

    }

    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return null;
    }

    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {

    }

    public void setHoldability(int holdability) throws SQLException {

    }

    public int getHoldability() throws SQLException {
        return 0;
    }

    public Savepoint setSavepoint() throws SQLException {
        return null;
    }

    public Savepoint setSavepoint(String name) throws SQLException {
        return null;
    }

    public void rollback(Savepoint savepoint) throws SQLException {

    }

    public void releaseSavepoint(Savepoint savepoint) throws SQLException {

    }

    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return null;
    }

    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return null;
    }

    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return null;
    }

    public Clob createClob() throws SQLException {
        return null;
    }

    public Blob createBlob() throws SQLException {
        return null;
    }

    public NClob createNClob() throws SQLException {
        return null;
    }

    public SQLXML createSQLXML() throws SQLException {
        return null;
    }

    public boolean isValid(int timeout) throws SQLException {
        return false;
    }

    public void setClientInfo(String name, String value) throws SQLClientInfoException {

    }

    public void setClientInfo(Properties properties) throws SQLClientInfoException {

    }

    public String getClientInfo(String name) throws SQLException {
        return null;
    }

    public Properties getClientInfo() throws SQLException {
        return null;
    }

    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return null;
    }

    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return null;
    }

    public void setSchema(String schema) throws SQLException {

    }

    public String getSchema() throws SQLException {
        return null;
    }

    public void abort(Executor executor) throws SQLException {

    }

    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {

    }

    public int getNetworkTimeout() throws SQLException {
        return 0;
    }

    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

查看輸出結果:

2020-05-28 23:37:18:687 [Thread-2] 等待連接
2020-05-28 23:37:18:689 [Thread-0] 獲取連接 TestConnection{name='連接1'}
2020-05-28 23:37:18:689 [Thread-1] 獲取連接 TestConnection{name='連接0'}
2020-05-28 23:37:18:716 [Thread-4] 等待連接
2020-05-28 23:37:18:716 [Thread-3] 等待連接
2020-05-28 23:37:19:717 [Thread-1] 釋放連接TestConnection{name='連接0'}
2020-05-28 23:37:19:717 [Thread-0] 釋放連接TestConnection{name='連接1'}
2020-05-28 23:37:19:718 [Thread-3] 獲取連接 TestConnection{name='連接0'}
2020-05-28 23:37:19:718 [Thread-2] 等待連接
2020-05-28 23:37:19:718 [Thread-4] 獲取連接 TestConnection{name='連接1'}
2020-05-28 23:37:20:732 [Thread-3] 釋放連接TestConnection{name='連接0'}
2020-05-28 23:37:20:732 [Thread-2] 獲取連接 TestConnection{name='連接0'}
2020-05-28 23:37:20:732 [Thread-4] 釋放連接TestConnection{name='連接1'}
2020-05-28 23:37:21:732 [Thread-2] 釋放連接TestConnection{name='連接0'}

 好像沒有什麼問題,歡迎夥伴們交流討論,等你哦~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章