數據庫開發 - 數據庫鏈接池

#數據庫鏈接池 ##創建鏈接 經過conncetion = DrvierManager.getConnection()獲取數據庫鏈接,這段代碼經過對應的JDBC驅動,完成了客戶端與服務器的大量交互。因爲數據庫鏈接通過4次,才能鏈接成功。則在複雜的網絡環境下,創建數據鏈接的網絡開銷比較高。 ###MySQL獲取數據庫鏈接mysql

  • 1.請求創建鏈接
    MySQL客戶端向MySQL服務器發起請求創建鏈接
  • 2.發送隨機密碼種子
    服務器端會隨機生成一組密碼種子返回給客戶端
  • 3.發送加密密碼
    客戶端利用密碼種子和鏈接數據庫的密碼,按照約定的加密算法,能夠計算獲得加密的密碼,而後在將這個密碼發送到MySQL服務器端進行驗證
  • 4.鏈接創建成功
    MySQL服務器通過對加密密碼的驗證,鏈接創建成功

輸入圖片說明

##多線程數據庫訪問 在實際業務場景中,多個用戶訪問Java應用程序,咱們會啓動線程去處理用戶請求,若是要訪問數據庫,則咱們須要建立connection對象,創建到後端數據庫的物理鏈接,在SQL執行結束以後,隨着close方法結束,數據庫鏈接被銷燬,線程也會被釋放。算法

當用戶再次訪問時,會重複這個過程,這個過程花費大量的時間創建鏈接。sql

##鏈接複用 因爲創建鏈接須要花費大量時間,咱們可使用數據庫鏈接池對鏈接進行重複使用。每一個線程在使用數據庫鏈接後並非當即銷燬。而是把數據庫鏈接交給下一個須要訪問數據庫的線程。多個線程共用相同的物理鏈接。實現鏈接的複用。
咱們以鏈接池的形式來管理數據庫鏈接,每一個須要訪問數據庫的線程,須要從鏈接池中租借數據庫鏈接。使用完畢之後,在歸還給鏈接池,這樣咱們就能夠實現鏈接的重複使用。避免每次訪問數據庫都要創建數據庫鏈接。
咱們從建立數據庫鏈接改變爲租借數據庫鏈接!數據庫

輸入圖片說明

##創建鏈接 鏈接池存在的第二個重要緣由,數據庫服務端在處理咱們的數據庫請求時,都會在服務器端分配必定的資源,好比說內存用來保存數據庫查詢的結果。在請求處理結束之後,這些資源也會被釋放,服務器端的資源老是有限的,不可能無限制的去分配。當同時有多個數據庫請求去訪問數據庫時,服務器端可以處理的鏈接數是有限制的。當超過最大可分配的資源時,就會出現服務器宕機的問題。爲了限制併發訪問的鏈接數。數據庫服務器端通常會設置最大鏈接數。若是超過最大鏈接數,就會拋出too many connection的異常。apache

輸入圖片說明

##限制鏈接 雖然服務器端作了必要的保護限制,可是對於應用程序,一方面服務器端直接拋SQL服務異常,對Java程序的處理不夠友好。Java程序必需要捕獲這些異常,進行異常處理。第二點,咱們也不該當僅僅依靠服務器的最大鏈接數限制。咱們應當在數據庫訪問客戶端的時候,就實現這種限制。必須被有序可控的被線程使用。一旦發生異常,咱們也多了一種保護手段。
因此咱們須要在Java客戶端程序就實現業務線程排隊獲取數據庫練級。同時獲取數據庫鏈接的線程數,起到限流對後端數據庫保護的措施。同時鏈接數過多,對後端數據庫的性能形成嚴重的影響。應爲鏈接數的增多,後端數據庫就會存在更多的鎖的衝突與檢測。加大數據庫服務器端資源的消耗。咱們應當保證應用程序可控獲取數據庫鏈接。後端

輸入圖片說明

##鏈接池 使用鏈接池兩個最重要的緣由:服務器

鏈接池實際上就是一組Java Jar包,介於Java應用程序與JDBC數據庫物理鏈接之間。負責幫助應用程序管理JDBC鏈接。經過鏈接池暴露的接口,鏈接池能夠獲取數據庫鏈接,使用完畢後,將數據庫鏈接歸還給數據庫鏈接池。網絡

鏈接池對JDBC進行有效的管理。當鏈接不足時,會自動建立鏈接。在空閒的鏈接比較多的時候,會自動的銷燬連接。在多個線程同時去獲取數據庫鏈接時,鏈接池還提供排隊等待的功能。可以保證應用程序可以有序的獲取數據庫鏈接。多線程

輸入圖片說明

##鏈接池DBCP併發

DBCP鏈接池是Apache開源的Java鏈接池項目,同時是Tomcat鏈接池組件。同時在互聯網企業中,應用最爲普遍。DBCP鏈接池包括三個Java Jar包。

輸入圖片說明

##DBCP官網 Apache Commons
DBCP

能夠從Apache官方網站下載Java Jar包,也能夠在mvnrepo網站下載。注意:DBCP三個Jar都是必須的。

##建立鏈接池對象 DBCP鏈接池使用叫作BasicDataSource對象來表示一個鏈接池。首先咱們要建立BasicDataSource對象,因爲JDBC鏈接池只是JDBC鏈接的管理單位。底層數據庫訪問依然經過JDBC鏈接實現。因此咱們必需要告訴DBCP必要的信息,才能讓DBCP去幫助咱們去建立鏈接,這些信息與咱們去建立JDBC鏈接的信息是一致的。

輸入圖片說明

##DBCP初始化

public static BasicDataSource basicDataSource = null;

    public final static String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    public final static String DB_URL = "jdbc:mysql://192.168.1.200/test";
    public final static String USER = "root";
    public final static String PASSWORD = "dVHJtG0T:pf*";

    public void init()
    {
        basicDataSource = new BasicDataSource();
        basicDataSource.setUrl(DB_URL);
        basicDataSource.setDriverClassName(JDBC_DRIVER);
        basicDataSource.setUsername(USER);
        basicDataSource.setPassword(PASSWORD);
    }

##獲取數據庫鏈接 輸入圖片說明
咱們能夠注意到,這裏除了獲取鏈接外,和JDBC代碼方式沒有任何區別。

Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            connection = basicDataSource.getConnection();

            statement = connection.createStatement();
            resultSet = statement.executeQuery("SELECT * FROM user");

            while(resultSet.next())
            {
                String username = resultSet.getString("UserName");
                System.out.println("[UserName]:" + username);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            try {
                resultSet.close();
                statement.close();
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }

##高級配置 在實際開發過程當中,咱們還會去設置一些鏈接數據庫的參數,來幫助咱們優化鏈接池,提升數據庫訪問的性能。

  • setInitialSize()
    當咱們應用第一次訪問數據庫時,會發生很慢的狀況。這是因爲數據庫鏈接池中沒有數據庫鏈接。須要去建立鏈接,此過程須要花費較多的時間。當鏈接建立好之後,後續的數據庫訪問就不會再去建立數據庫鏈接。速度相對較快。InitialSize就是隻在數據庫鏈接池建立時,預製一些數據庫鏈接。來保證應用程序第一次訪問時,鏈接池中就有必定數量的數據庫鏈接。第一次訪問就不會變的很慢。能夠經過InitialSize設置鏈接池預製的鏈接數。通常設置成預期業務訪問量,是比較合適的。
  • setMaxTotal()
    當鏈接池中沒有空閒的鏈接,又有線程須要去訪問數據庫時,鏈接池此時會建立一個新的數據庫鏈接。可是此時,鏈接數已經達到了MaxTotal設定的最大值。則鏈接池就不會爲等待線程新建數據庫鏈接。而是強制讓該線程進入等待隊列。直到有其餘線程歸還數據庫鏈接,再進行分配。MaxTotal起到限流保護數據庫的做用,進入隊列的線程不可能無限制的等待。
  • setMaxWaitMillis()
    經過設置MaxWaitMillis來設置隊列線程最大的等待時間,若是超過等待時間,則會獲得SQLExecption異常。
  • setMaxIdle()
    當應用程序使用完線程鏈接之後,將鏈接歸還給鏈接池,若是此時空間鏈接池超過了MaxIdle的值時,則鏈接池會自動銷燬這個數據庫鏈接。這樣減小後端數據庫的鏈接數,減小資源的損耗。

輸入圖片說明

  • setMinIdle()
    固然如何鏈接池中的空閒鏈接低於MinIdle時,則會自動觸發和建立數據庫鏈接。來保證鏈接池有足夠的鏈接被租借。通常來講,咱們爲了不數據庫鏈接池頻繁的建立和銷燬鏈接。建議吧MinIdleMaxIdle設置爲相同的值。

##DBCP按期檢查 數據庫服務爲了釋放,空閒等待的資源,默認會關閉超過必定時間閾值的數據庫鏈接。MySQL數據庫服務器端默認會關閉時間超過,8個小時的鏈接。可是這時,數據庫鏈接池端並不知道數據庫鏈接被關閉。當線程向數據庫鏈接池租借數據庫鏈接時,鏈接池會將失效的數據庫鏈接,租借給應用程序。線程在使用這樣的數據庫鏈接,就會拋出SQLException異常。爲了防止以上狀況發生,儘可能保持數據庫鏈接池鏈接的有效性。則按期對數據庫鏈接池的空閒鏈接的時間進行檢查。在服務器端關閉鏈接以前,咱們保證,會把這個鏈接銷燬掉,在建立新的鏈接。來保證線程到數據庫鏈接池租借的鏈接都是有效的。

  • setTestWhileIdle(True)
    開啓按期檢查空間數據庫鏈接有效性
  • setMinEvictableIdleTimeMillis()
    銷燬鏈接最小空閒時間,當鏈接的空間時間超過該值時,會被鏈接池自動的銷燬。建議:MinEvictabledleTimeMillis要小於數據庫服務器端自動關閉的預製時間,MySQL小於8個小時,咱們纔可以檢測空閒時間超過該值。才能保證主動關閉鏈接。
  • setTimeBetweenEvictionRunsMillis()
    檢查運行時間的間隔

##驗證鏈接池有效 鏈接池幫助咱們起到限流的做用,實現鏈接的重複使用。對比使用鏈接池與JDBC的後端鏈接數。

咱們經過MySQLshow processlist來能夠看到線程數據庫鏈接的狀況。

若是啓動十個線程,則JDBC方式會啓動十個數據庫鏈接。 而若是使用數據庫鏈接池,限制數據庫鏈接數,則只有兩個數據庫鏈接。

##總結 使用數據庫鏈接提升數據庫訪問的效率。起到對後端數據庫進行限流保護的做用。

相關文章
相關標籤/搜索