1. 程式人生 > >mysql資料庫連線池

mysql資料庫連線池

[轉]https://www.cnblogs.com/aspir...一、什麼是資料庫連線池?官方:資料庫連線池(Connection pooling)是程式啟動時建立足夠的資料庫連線,並將這些連線組成一個連線池,由程式動態地對池中的連線進行申請,使用,釋放。個人理解:建立資料庫連線是一個很耗時的操作,也容易對資料庫造成安全隱患。所以,在程式初始化的時候,集中建立多個數據庫連線,並把他們集中管理,供程式使用,可以保證較快的資料庫讀寫速度,還更加安全可靠。

二、傳統的連線機制與資料庫連線池的執行機制區別 傳統統連結: 一般來說,Java應用程式訪問資料庫的過程是:

  ①裝載資料庫驅動程式;

  ②通過JDBC建立資料庫連線;

  ③訪問資料庫,執行SQL語句;

  ④斷開資料庫連線。

使用了資料庫連線池的機制:(1) 程式初始化時建立連線池(2) 使用時向連線池申請可用連線(3) 使用完畢,將連線返還給連線池(4) 程式退出時,斷開所有連線,並釋放資源

clipboard.png

一. 為何要使用資料庫連線池假設網站一天有很大的訪問量,資料庫伺服器就需要為每次連線建立一次資料庫連線,極大的浪費資料庫的資源,並且極易造成資料庫伺服器記憶體溢位、拓機。資料庫連線是一種關鍵的有限的昂貴的資源,這一點在多使用者的網頁應用程式中體現的尤為突出.對資料庫連線的管理能顯著影響到整個應用程式的伸縮性和健壯性,影響到程式的效能指標.資料庫連線池正式針對這個問題提出來的.資料庫連線池負責分配,管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是重新建立一個。

資料庫連線池在初始化時將建立一定數量的資料庫連線放到連線池中, 這些資料庫連線的數量是由最小資料庫連線數來設定的.無論這些資料庫連線是否被使用,連線池都將一直保證至少擁有這麼多的連線數量.連線池的最大資料庫連線數量限定了這個連線池能佔有的最大連線數,當應用程式向連線池請求的連線數超過最大連線數量時,這些請求將被加入到等待佇列中.

  資料庫連線池的最小連線數和最大連線數的設定要考慮到以下幾個因素:

  1, 最小連線數:是連線池一直保持的資料庫連線,所以如果應用程式對資料庫連線的使用量不大,將會有大量的資料庫連線資源被浪費.  2, 最大連線數:是連線池能申請的最大連線數,如果資料庫連線請求超過次數,後面的資料庫連線請求將被加入到等待佇列中,這會影響以後的資料庫操作  3, 如果最小連線數與最大連線數相差很大:那麼最先連線請求將會獲利,之後超過最小連線數量的連線請求等價於建立一個新的資料庫連線.不過,這些大於最小連線數的資料庫連線在使用完不會馬上被釋放,他將被 放到連線池中等待重複使用或是空間超時後被釋放.

二、使用資料庫連線池的關鍵點1、併發問題  為了使連線管理服務具有最大的通用性,必須考慮多執行緒環境,即併發問題。這個問題相對比較好解決,因為各個語言自身提供了對併發管理的支援像java,c#等等,使用synchronized(java)lock(C#)關鍵字即可確保執行緒是同步的。使用方法可以參考,相關文獻。

2、事務處理DB連線池必須要確保某一時間內一個 conn 只能分配給一個執行緒。不同 conn 的事務是相互獨立的。

  我們知道,事務具有原子性,此時要求對資料庫的操作符合“ALL-ALL-NOTHING”原則,即對於一組SQL語句要麼全做,要麼全不做。   我們知道當2個執行緒共用一個連線Connection物件,而且各自都有自己的事務要處理時候,對於連線池是一個很頭疼的問題,因為即使Connection類提供了相應的事務支援,可是我們仍然不能確定那個資料庫操作是對應那個事務的,這是由於我們有2個執行緒都在進行事務操作而引起的。為此我們可以使用每一個事務獨佔一個連線來實現,雖然這種方法有點浪費連線池資源但是可以大大降低事務管理的複雜性。

3、連線池的分配與釋放  連線池的分配與釋放,對系統的效能有很大的影響。合理的分配與釋放,可以提高連線的複用度,從而降低建立新連線的開銷,同時還可以加快使用者的訪問速度。   對於連線的管理可使用一個List。即把已經建立的連線都放入List中去統一管理。每當使用者請求一個連線時,系統檢查這個List中有沒有可以分配的連線。如果有就把那個最合適的連線分配給他(如何能找到最合適的連線文章將在關鍵議題中指出);如果沒有就丟擲一個異常給使用者,List中連線是否可以被分配由一個執行緒來專門管理捎後我會介紹這個執行緒的具體實現。

4、連線池的配置與維護  連線池中到底應該放置多少連線,才能使系統的效能最佳?系統可採取設定最小連線數(minConnection)和最大連線數(maxConnection)等引數來控制連線池中的連線。比方說,最小連線數是系統啟動時連線池所建立的連線數。如果建立過多,則系統啟動就慢,但建立後系統的響應速度會很快;如果建立過少,則系統啟動的很快,響應起來卻慢。這樣,可以在開發時,設定較小的最小連線數,開發起來會快,而在系統實際使用時設定較大的,因為這樣對訪問客戶來說速度會快些。最大連線數是連線池中允許連線的最大數目,具體設定多少,要看系統的訪問量,可通過軟體需求上得到。   如何確保連線池中的最小連線數呢?有動態和靜態兩種策略。動態即每隔一定時間就對連線池進行檢測,如果發現連線數量小於最小連線數,則補充相應數量的新連線,以保證連線池的正常運轉。靜態是發現空閒連線不夠時再去檢查。

三、使用資料庫連線池的優勢和其工作原理1、連線池的優勢連線池用於建立和管理資料庫連線的緩衝池技術,緩衝池中的連線可以被任何需要他們的執行緒使用。當一個執行緒需要用JDBC對一個數據庫操作時,將從池中請求一個連線。當這個連線使用完畢後,將返回到連線池中,等待為其他的執行緒服務。

連線池的主要優點有以下三個方面。

第一、減少連線建立時間。連線池中的連線是已準備好的、可重複使用的,獲取後可以直接訪問資料庫,因此減少了連線建立的次數和時間。

第二、簡化的程式設計模式。當使用連線池時,每一個單獨的執行緒能夠像建立一個自己的JDBC連線一樣操作,允許使用者直接使用JDBC程式設計技術。

第三、控制資源的使用。如果不使用連線池,每次訪問資料庫都需要建立一個連線,這樣系統的穩定性受系統連線需求影響很大,很容易產生資源浪費和高負載異常。連線池能夠使效能最大化,將資源利用控制在一定的水平之下。連線池能控制池中的連線數量,增強了系統在大量使用者應用時的穩定性。

2、連線池的工作原理下面,簡單的闡述下連線池的工作原理。

連線池技術的核心思想是連線複用,通過建立一個數據庫連線池以及一套連線使用、分配和管理策略,使得該連線池中的連線可以得到高效、安全的複用,避免了資料庫連線頻繁建立、關閉的開銷。

連線池的工作原理主要由三部分組成,分別為連線池的建立、連線池中連線的使用管理、連線池的關閉。

第一、連線池的建立。一般在系統初始化時,連線池會根據系統配置建立,並在池中建立了幾個連線物件,以便使用時能從連線池中獲取。連線池中的連線不能隨意建立和關閉,這樣避免了連線隨意建立和關閉造成的系統開銷。Java中提供了很多容器類可以方便的構建連線池,例如Vector、Stack等。

第二、連線池的管理。連線池管理策略是連線池機制的核心,連線池內連線的分配和釋放對系統的效能有很大的影響。其管理策略是:

當客戶請求資料庫連線時,首先檢視連線池中是否有空閒連線,如果存在空閒連線,則將連線分配給客戶使用;如果沒有空閒連線,則檢視當前所開的連線數是否已經達到最大連線數,如果沒達到就重新建立一個連線給請求的客戶;如果達到就按設定的最大等待時間進行等待,如果超出最大等待時間,則丟擲異常給客戶。當客戶釋放資料庫連線時,先判斷該連線的引用次數是否超過了規定值,如果超過就從連線池中刪除該連線,否則保留為其他客戶服務。

該策略保證了資料庫連線的有效複用,避免頻繁的建立、釋放連線所帶來的系統資源開銷。

第三、連線池的關閉。當應用程式退出時,關閉連線池中所有的連線,釋放連線池相關的資源,該過程正好與建立相反。

3、常用的連線池:

 (1) dbcp

dbcp可能是使用最多的開源連線池,原因大概是因為配置方便,而且很多開源和tomcat應用例子都是使用的這個連線池吧。這個連線池可以設定最大和最小連線,連線等待時間等,基本功能都有。這個連線池的配置參見附件壓縮包中的:dbcp.xml使用評價:在具體專案應用中,發現此連線池的持續執行的穩定性還是可以,不過速度稍慢,在大併發量的壓力下穩定性有所下降,此外不提供連線池監控

常用的引數(阿里面試問常用的引數):

我們來看DBCP 的例子, 然後根據例子來分析:

複製程式碼複製程式碼

連線設定

driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/day14username=rootpassword=abc

<!-- 初始化連線 -->

initialSize=10

最大連線數量

maxActive=50

<!-- 最大空閒連線 -->

maxIdle=20

<!-- 最小空閒連線 -->

minIdle=5

<!-- 超時等待時間以毫秒為單位 60000毫秒/1000等於60秒 -->

maxWait=60000

JDBC驅動建立連線時附帶的連線屬性屬性的格式必須為這樣:[屬性名=property;]

注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裡不需要包含他們。

connectionProperties=useUnicode=true;characterEncoding=utf8

指定由連線池所建立的連線的自動提交(auto-commit)狀態。

defaultAutoCommit=true

driver default 指定由連線池所建立的連線的只讀(read-only)狀態。

如果沒有設定該值,則“setReadOnly”方法將不被呼叫。(某些驅動並不支援只讀模式,如:Informix)

defaultReadOnly=

driver default 指定由連線池所建立的連線的事務級別(TransactionIsolation)。

可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

defaultTransactionIsolation=REPEATABLE_READ

DBCP配置檔案複製程式碼複製程式碼配置引數詳解:

MaxActive,連線池的最大資料庫連線數。設為0表示無限制。maxActive是最大啟用連線數,這裡取值為20,表示同時最多有20個數據庫連 maxIdle 連線池中最多可空閒maxIdle個連線,maxIdle是最大的空閒連線數,這裡取值為20,表示即使沒有資料庫連線時依然可以保持20空閒的連線,而不被清除,隨時處於待命狀態minIdle 連線池中最少空閒maxIdle個連線 initialSize 初始化連線數目 maxWait 連線池中連線用完時,新的請求等待時間,毫秒 MaxWait是最大等待秒鐘數,這裡取值-1,表示無限等待,直到超時為止,也可取值9000,表示9秒後超時。maxIdle,最大空閒數,資料庫連線的最大空閒時間。超過空閒時間,資料庫連線將被標記為不可用,然後被釋放。設為0表示無限制。

(2) c3p0c3p0是另外一個開源的連線池,在業界也是比較有名的,這個連線池可以設定最大和最小連線,連線等待時間等,基本功能都有。這個連線池的配置參見附件壓縮包中的:c3p0.xml。使用評價:在具體專案應用中,發現此連線池的持續執行的穩定性相當不錯,在大併發量的壓力下穩定性也有一定保證,

      此外不提供連線池監控。          

1.Apache commons-dbcp 連線池

    下載:http://commons.apache.org/proper/commons-dbcp/ 

   2.c3p0 資料庫連線池

    下載:http://sourceforge.net/projects/c3p0/

程式開發過程中,存在很多問題:

首先,每一次web請求都要建立一次資料庫連線。建立連線是一個費時的活動,每次都得花費0.05s~1s的時間,而且系統還要分配記憶體資源。這個時間對於一次或幾次資料庫操作,或許感覺不出系統有多大的開銷。

可是對於現在的web應用,尤其是大型電子商務網站,同時有幾百人甚至幾千人線上是很正常的事。在這種情況下,頻繁的進行資料庫連線操作勢必佔用很多的系統資源,網站的響應速度必定下降,嚴重的甚至會造成伺服器的崩潰。不是危言聳聽,這就是制約某些電子商務網站發展的技術瓶頸問題。其次,對於每一次資料庫連線,使用完後都得斷開。否則,如果程式出現異常而未能關閉,將會導致資料庫系統中的記憶體洩漏,最終將不得不重啟資料庫

 通過上面的分析,我們可以看出來,“資料庫連線”是一種稀缺的資源,為了保障網站的正常使用,應該對其進行妥善管理。其實我們查詢完資料庫後,如果不關閉連線,而是暫時存放起來,當別人使用時,把這個連線給他們使用。就避免了一次建立資料庫連線和斷開的操作時間消耗。

資料庫連線池的基本思想:就是為資料庫連線建立一個“緩衝池”。預先在緩衝池中放入一定數量的連線,當需要建立資料庫連線時,只需從“緩衝池”中取出一個,使用完畢之後再放回去。我們可以通過設定連線池最大連線數來防止系統無盡的與資料庫連線

建立資料庫連線池大概有3個步驟:

① 建立ConnectionPool例項,並初始化建立10個連線,儲存在Vector中(執行緒安全)單例模式實現② 實現getConnection()從連線庫中獲取一個可用的連線③ returnConnection(conn) 提供將連線放回連線池中方法

  連線池的實現

  1、連線池模型

  本文討論的連線池包括一個連線池類(DBConnectionPool)和一個連線池管理類(DBConnetionPoolManager)。連線池類是對某一資料庫所有連線的“緩衝池”,主要實現以下功能:①從連線池獲取或建立可用連線;②使用完畢之後,把連線返還給連線池;③在系統關閉前,斷開所有連線並釋放連線佔用的系統資源;④還能夠處理無效連線(原來登記為可用的連線,由於某種原因不再可用,如超時,通訊問題),並能夠限制連線池中的連線總數不低於某個預定值和不超過某個預定值。

  連線池管理類是連線池類的外覆類(wrapper),符合單例模式,即系統中只能有一個連線池管理類的例項。其主要用於對多個連線池物件的管理,具有以下功能:①裝載並註冊特定資料庫的JDBC驅動程式;②根據屬性檔案給定的資訊,建立連線池物件;③為方便管理多個連線池物件,為每一個連線池物件取一個名字,實現連線池名字與其例項之間的對映;④跟蹤客戶使用連線情況,以便需要是關閉連線釋放資源。連線池管理類的引入主要是為了方便對多個連線池的使用和管理,如系統需要連線不同的資料庫,或連線相同的資料庫但由於安全性問題,需要不同的使用者使用不同的名稱和密碼。

連線池原始碼:

ConnectionPool.Java

View Code

ConnectionPoolUtils.java

複製程式碼複製程式碼/連線池工具類,返回唯一的一個數據庫連線池物件,單例模式/ public class ConnectionPoolUtils {

private ConnectionPoolUtils(){};//私有靜態方法  
private static ConnectionPool poolInstance = null;  
public static ConnectionPool GetPoolInstance(){  
    if(poolInstance == null) {  
        poolInstance = new ConnectionPool(                     
                "com.mysql.jdbc.Driver",                   
                "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8",                
                "root", "123456");  
        try {  
            poolInstance.createPool();  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
    return poolInstance;  
}  

} 複製程式碼複製程式碼ConnectionPoolTest.java

View Code

DBCPUtils:

複製程式碼複製程式碼public class DBCPUtils {

private static DataSource ds;//定義一個連線池物件
static{
    try {
        Properties pro = new Properties();
        pro.load(DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"));
        ds = BasicDataSourceFactory.createDataSource(pro);//得到一個連線池物件
    } catch (Exception e) {
        throw new ExceptionInInitializerError("初始化連線錯誤,請檢查配置檔案!");
    }
}
//從池中獲取一個連線
public static Connection getConnection() throws SQLException{
    return ds.getConnection();
}

public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
    if(rs!=null){
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    if(stmt!=null){
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    if(conn!=null){
        try {
            conn.close();//關閉
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

}複製程式碼複製程式碼

6.匯入的jar包

commons-dbcp.jar:DBCP實現要匯入的jar

commons-pool.jar: 連線池實現的依賴類

commons-collections.jar :連線池實現的集合類