大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 學習攻略 Java學習 Java連接池的簡單介紹

Java連接池的簡單介紹

更新時間:2022-09-02 11:46:06 來源:動力節點 瀏覽1555次

Java連接池是什么?動力節點小編來為大家解答。

概述

連接池是一種眾所周知的數據訪問模式。其主要目的是減少執行數據庫連接和讀/寫數據庫操作所涉及的開銷。

在最基本的層面上, 連接池是一種數據庫連接緩存實現 ,可以根據特定需求進行配置。

在本教程中,我們將討論一些流行的連接池框架。然后我們將學習如何從頭開始實現我們自己的連接池。

為什么是連接池?

當然,這個問題是修辭性的。

如果我們分析典型數據庫連接生命周期中涉及的步驟順序,我們就會明白為什么:

使用數據庫驅動程序打開到數據庫的連接

打開TCP 套接字以讀取/寫入數據

通過套接字讀取/寫入數據

關閉連接

關閉插座

很明顯,數據庫連接是相當昂貴的操作,因此,在每個可能的用例中都應該減少到最低限度(在邊緣情況下,只是避免)。

這就是連接池實現發揮作用的地方。

通過簡單地實現一個數據庫連接容器,它允許我們重用許多現有的連接,我們可以有效地節省執行大量昂貴的數據庫旅行的成本。這提高了我們的數據庫驅動應用程序的整體性能。

JDBC 連接池框架

從實用的角度來看,考慮到已經可用的“企業就緒”連接池框架的數量,從頭開始實施連接池是沒有意義的。

從教學的角度來看,這是本文的目標,事實并非如此。

盡管如此,在我們學習如何實現一個基本的連接池之前,我們將首先展示一些流行的連接池框架。

1.Apache Commons DBCP

讓我們從Apache Commons DBCP Component開始,這是一個功能齊全的連接池 JDBC 框架:

public class DBCPDataSource {   
    private static BasicDataSource ds = new BasicDataSource();    
    static {
        ds.setUrl("jdbc:h2:mem:test");
        ds.setUsername("user");
        ds.setPassword("password");
        ds.setMinIdle(5);
        ds.setMaxIdle(10);
        ds.setMaxOpenPreparedStatements(100);
    }    
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }    
    private DBCPDataSource(){ }
}

在這種情況下,我們使用帶有靜態塊的包裝類來輕松配置 DBCP 的屬性。

以下是如何獲得與DBCPDataSource類的池連接:

Connection con = DBCPDataSource.getConnection();

2.HikariCP

現在讓我們看看HikariCP ,這是一個由Brett Wooldridge創建的閃電般快速的 JDBC 連接池框架

public class HikariCPDataSource {    
    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;    
    static {
        config.setJdbcUrl("jdbc:h2:mem:test");
        config.setUsername("user");
        config.setPassword("password");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        ds = new HikariDataSource(config);
    }    
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }    
    private HikariCPDataSource(){}
}

同樣,這里是如何獲得與HikariCPDataSource類的池連接:

Connection con = HikariCPDataSource.getConnection();

3.C3P0

這篇評論的最后一篇是C3P0,這是一個由 Steve Waldman 開發的強大的 JDBC4 連接和語句池框架:

public class C3p0DataSource {
    private static ComboPooledDataSource cpds = new ComboPooledDataSource();
    static {
        try {
            cpds.setDriverClass("org.h2.Driver");
            cpds.setJdbcUrl("jdbc:h2:mem:test");
            cpds.setUser("user");
            cpds.setPassword("password");
        } catch (PropertyVetoException e) {
            // handle the exception
        }
    }    
    public static Connection getConnection() throws SQLException {
        return cpds.getConnection();
    }    
    private C3p0DataSource(){}
}

正如預期的那樣,使用C3p0DataSource類獲取池連接類似于前面的示例:

Connection con = C3p0DataSource.getConnection();

一個簡單的實現

為了更好地理解連接池的底層邏輯,讓我們創建一個簡單的實現。

我們將從僅基于一個單一接口的松散耦合設計開始:

public interface ConnectionPool {
    Connection getConnection();
    boolean releaseConnection(Connection connection);
    String getUrl();
    String getUser();
    String getPassword();
}

ConnectionPool接口定義了基本連接池的公共 API 。

現在讓我們創建一個提供一些基本功能的實現,包括獲取和釋放池連接:

public class BasicConnectionPool 
  implements ConnectionPool {
    private String url;
    private String user;
    private String password;
    private List<Connection> connectionPool;
    private List<Connection> usedConnections = new ArrayList<>();
    private static int INITIAL_POOL_SIZE = 10;    
    public static BasicConnectionPool create(
      String url, String user, 
      String password) throws SQLException { 
        List<Connection> pool = new ArrayList<>(INITIAL_POOL_SIZE);
        for (int i = 0; i < INITIAL_POOL_SIZE; i++) {
            pool.add(createConnection(url, user, password));
        }
        return new BasicConnectionPool(url, user, password, pool);
    }    
    // standard constructors    
    @Override
    public Connection getConnection() {
        Connection connection = connectionPool
          .remove(connectionPool.size() - 1);
        usedConnections.add(connection);
        return connection;
    }    
    @Override
    public boolean releaseConnection(Connection connection) {
        connectionPool.add(connection);
        return usedConnections.remove(connection);
    }    
    private static Connection createConnection(
      String url, String user, String password) 
      throws SQLException {
        return DriverManager.getConnection(url, user, password);
    }   
    public int getSize() {
        return connectionPool.size() + usedConnections.size();
    }
    // standard getters
}

雖然非常幼稚,但BasicConnectionPool類提供了我們期望從典型連接池實現中獲得的最小功能。

簡而言之,該類基于存儲10個連接的ArrayList初始化一個連接池,可以方便地重用。

還可以使用DriverManager類和Datasource實現創建 JDBC 連接。

由于保持連接數據庫的創建不可知要好得多,我們在create()靜態工廠方法中使用了前者。

在這種情況下,我們將方法放在BasicConnectionPool中 ,因為這是接口的唯一實現。

在具有多個ConnectionPool實現的更復雜的設計中,最好將其放置在接口中,從而獲得更靈活的設計和更高水平的內聚。

這里要強調的最相關的一點是,一旦創建了池,就會從池中獲取連接,因此無需創建新的。

此外,當一個連接被釋放時,它實際上會返回到池中,因此其他客戶端可以重用它。

沒有與底層數據庫的進一步交互,例如顯式調用Connection 的 close()方法。

使用BasicConnectionPool類

正如預期的那樣,使用我們的BasicConnectionPool類很簡單。

讓我們創建一個簡單的單元測試并獲得一個池化的內存H2連接:

@Test
public whenCalledgetConnection_thenCorrect() {
    ConnectionPool connectionPool = BasicConnectionPool
      .create("jdbc:h2:mem:test", "user", "password"); 
    assertTrue(connectionPool.getConnection().isValid(1));
}

進一步的改進和重構

當然,還有很多空間可以調整/擴展我們的連接池實現的當前功能。

例如,我們可以重構getConnection()方法并添加對最大池大小的支持。如果所有可用連接都被占用,并且當前池大小小于配置的最大值,則該方法將創建一個新連接。

我們還可以驗證從池中獲得的連接是否仍然存在,然后再將其傳遞給客戶端:

@Override
public Connection getConnection() throws SQLException {
    if (connectionPool.isEmpty()) {
        if (usedConnections.size() < MAX_POOL_SIZE) {
            connectionPool.add(createConnection(url, user, password));
        } else {
            throw new RuntimeException(
              "Maximum pool size reached, no available connections!");
        }
    }
    Connection connection = connectionPool
      .remove(connectionPool.size() - 1);
    if(!connection.isValid(MAX_TIMEOUT)){
        connection = createConnection(url, user, password);
    }
    usedConnections.add(connection);
    return connection;
}

請注意,該方法現在拋出SQLException,這意味著我們還必須更新接口簽名。

或者我們可以添加一個方法來優雅地關閉我們的連接池實例:

public void shutdown() throws SQLException {
    usedConnections.forEach(this::releaseConnection);
    for (Connection c : connectionPool) {
        c.close();
    }
    connectionPool.clear();
}

在生產就緒的實現中,連接池應該提供一堆額外的功能,例如跟蹤當前正在使用的連接的能力,支持準備好的語句池等等。

提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 成人午夜影院在线观看 | 激情福利网 | 亚洲精品国产第一区二区尤物 | 99久久99热久久精品免 | 一级片一级毛片 | 四虎黄色影院 | 久久综合日韩亚洲精品色 | 国产一级特黄aa级特黄裸毛片 | 欧美日韩另类综合 | 免费99视频 | 日韩中文字幕精品免费一区 | 久久777国产线看观看精品卜 | 欧美日韩一本 | 波多野结衣一二三区 | 亚洲毛片儿 | 久青草国产手机在线观 | 天天草夜夜骑 | 久久久精品视频在线观看 | 国产欧美久久久精品 | 亚洲一区二区三区福利在线 | 91资源在线| 免费播放欧美毛片 | 国产综合成人久久大片91 | 一级特黄特交牲大片 | 激情婷婷成人亚洲综合 | 性生活免费视频网站 | 亚洲欧洲视频在线观看 | 亚洲一区欧美二区 | 久草色播| 午夜论坛 | 久久久久久久综合日本亚洲 | 另类亚洲视频 | 中文国产欧美在线观看 | 精品一区精品二区 | 黑人巨大精品战中国美女 | 一级毛片视频播放 | 欧美日韩激情在线一区二区 | 午夜久久久精品 | 久久激情影院 | 久久综合中文字幕一区二区三区 | 亚洲欧美一区在线 |