#數據庫鏈接池 ##創建鏈接 經過conncetion = DrvierManager.getConnection()
獲取數據庫鏈接,這段代碼經過對應的JDBC驅動,完成了客戶端與服務器的大量交互。因爲數據庫鏈接通過4次,才能鏈接成功。則在複雜的網絡環境下,創建數據鏈接的網絡開銷比較高。 ###MySQL獲取數據庫鏈接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
時,則會自動觸發和建立數據庫鏈接。來保證鏈接池有足夠的鏈接被租借。通常來講,咱們爲了不數據庫鏈接池頻繁的建立和銷燬鏈接。建議吧MinIdle
和MaxIdle
設置爲相同的值。##DBCP按期檢查 數據庫服務爲了釋放,空閒等待的資源,默認會關閉超過必定時間閾值的數據庫鏈接。MySQL數據庫服務器端默認會關閉時間超過,8個小時的鏈接。可是這時,數據庫鏈接池端並不知道數據庫鏈接被關閉。當線程向數據庫鏈接池租借數據庫鏈接時,鏈接池會將失效的數據庫鏈接,租借給應用程序。線程在使用這樣的數據庫鏈接,就會拋出SQLException異常。爲了防止以上狀況發生,儘可能保持數據庫鏈接池鏈接的有效性。則按期對數據庫鏈接池的空閒鏈接的時間進行檢查。在服務器端關閉鏈接以前,咱們保證,會把這個鏈接銷燬掉,在建立新的鏈接。來保證線程到數據庫鏈接池租借的鏈接都是有效的。
setTestWhileIdle(True)
setMinEvictableIdleTimeMillis()
MinEvictabledleTimeMillis
要小於數據庫服務器端自動關閉的預製時間,MySQL小於8個小時,咱們纔可以檢測空閒時間超過該值。才能保證主動關閉鏈接。setTimeBetweenEvictionRunsMillis()
##驗證鏈接池有效 鏈接池幫助咱們起到限流的做用,實現鏈接的重複使用。對比使用鏈接池與JDBC的後端鏈接數。
咱們經過MySQLshow processlist
來能夠看到線程數據庫鏈接的狀況。
若是啓動十個線程,則JDBC方式會啓動十個數據庫鏈接。 而若是使用數據庫鏈接池,限制數據庫鏈接數,則只有兩個數據庫鏈接。
##總結 使用數據庫鏈接提升數據庫訪問的效率。起到對後端數據庫進行限流保護的做用。