c3p0 數據庫鏈接池手冊

c3p0 數據庫鏈接池手冊

定義

c3p0是一個成熟的、高併發的JDBC鏈接池,它隨Hibernate一同分發,但願提供一個優秀的J2EE企業級應用的數據源實現。html

使用情形

c3p0:java

  • 提供與基於驅動器管理的JDBC驅動和java.sql.DataSource視圖都兼容的獲取數據庫鏈接的類。
  • 透明化了數據源的鏈接和PreparedStatement,使傳統的驅動和任意的未入池的數據源都能得到環繞式的處理。
  • 適合綁定大量的基於JNDI的命名服務,它的數據源是可引用而且可序列化的。
  • 與JDBC2和JDBC3中定義的方法都兼容,開放了全部的必須屬性和大部分的可選屬性,提供了無參數的構造方法,實現了全部JDBC中定義的內部接口。

 

使用方法

必備環境

c3p0-0.9.5-pre8須要1.6.x或者更高版本的Java運行環境。mysql

安裝

lib/c3p0-0.9.5-pre8.jarlib/mchange-commons-java-0.27.jar兩個文件放入你的CLASSPASS下(或者你的類加載器可以加載的任何地方)。程序員

快速使用

建立數據源:web

1
2
3
4
5
6
7
import com.mchange.v2.c3p0.*;
...
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("dbuser");
cpds.setPassword("dbpassword");

 

[可選]:若是你須要開啓PreparedStatement池,你必須設置maxStatements和/或maxStatementsPerConnection兩個值(默認都爲0)。sql

1
cpds.setMaxStatements(180);

數據源底層的鏈接池將使用默認參數建立,你能夠對數據源進行任何操做。你能夠根據你的喜愛將數據源綁定到JNDI命名空間或者直接使用它。數據庫

當你使用完畢的時候,你能夠銷燬數據源:apache

1
cpds.close();

進階使用

c3p0提供標準的JDBC2數據源對象。用戶能夠在建立數據源對象時控制與池有關的、與命名有關的屬性等。全部的池管理操做在數據源對象被建立後都是對用戶徹底透明的。編程

建立c3p0數據源有三種方式:後端

  • 直接實例化、配置一個ComboPooledDataSource bean
  • 使用數據源工廠類。
  • 建立我的的帶池技術的數據源:直接實例化PoolBackedDataSource並設定它的ConectionPoolDataSource

若是不指定配置的話,c3p0將使用默認參數建立數據源。

一旦實例化成功,c3p0數據源就能夠和與JNDI標準兼容的命名服務綁定。

c3p0內置了硬編碼的配置,但你能夠經過建立一個c3p0.properties文件並將其放置在加載c3p0的jar文件的CLASSPATH(或類加載器)的頂級目錄下以覆蓋配置信息。
更多的配置信息請看下一章。

實例化並配置ComboPooledDataSource

實例化一個com.mchange.v2.c3p0.ComboPooledDataSource是建立c3p0池數據源的最直接方式。這是一個JavaBean風格的,擁有一個無參數的Public構造方法的類。確保你在使用它以前設定了jdbcUrl屬性。你也能夠根據須要設定userpassword屬性。若是你使用了未預加載的老式JDBC驅動,你還應當設定driverClass屬性。

1
2
3
4
5
6
7
8
9
10
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");
// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);
// The DataSource cpds is now a fully configured and usable pooled DataSource
...

任何一個c3p0 DataSource的實例的初狀態都取決於你提供的配置或者還原爲硬編碼的默認配置。

c3p0支持命名配置以配置多個數據源。

你能夠構造本身的com.mchange.v2.c3p0.ComboPooledDataSource命名配置:

1
ComboPooledDataSource cpds = new ComboPooledDataSource("intergalactoApp");

固然,你仍然能夠經過前面所述的編程方式來覆蓋配置信息。

使用數據源工廠類

此外,你還可使用靜態工廠類Com.mchange.v2.c3p0.DataSources來從傳統的JDBC驅動裏建立未入池的數據源,並用它來構造一個池化的數據源:

1
2
3
4
5
6
7
8
DataSource ds_unpooled = DataSources.unpooledDataSource(
"jdbc:postgresql://localhost/testdb", "swaldman", "test-password");
DataSource ds_pooled = DataSources.pooledDataSource( ds_unpooled );
// The DataSource ds_pooled is now a fully configured and usable pooled DataSource.
// The DataSource is using a default pool configuration, and Postgres' JDBC driver
// is presumed to have already been loaded via the jdbc.drivers system property or an
// explicit call to Class.forName("org.postgresql.Driver") elsewhere.
...

若是你使用了這個數據源工廠類,而且想要編程式覆蓋默認配置,你能夠經過提供一個map來實現:

1
2
3
4
5
6
7
8
9
10
11
12
DataSource ds_unpooled = DataSources.unpooledDataSource(
"jdbc:postgresql://localhost/testdb", "swaldman", "test-password");
Map overrides = new HashMap();
overrides.put("maxStatements", "200");//Stringified property values work
overrides.put("maxPoolSize", new Integer(50)); //"boxed primitives" also work

// create the PooledDataSource using the default configuration and our overrides
ds_pooled = DataSources.pooledDataSource( ds_unpooled, overrides ); 
// The DataSource ds_pooled is now a fully configured and usable pooled DataSource,
// with Statement caching enabled for a maximum of up to 200 statements and a maximum
// of 50 Connections.
...

若是你使用命名配置,你能夠指定一個命名來配置你的數據源:

1
2
// create the PooledDataSource using the a named configuration and specified overrides 
ds_pooled = DataSources.pooledDataSource(ds_unpooled, "intergalactoAppConfig", overrides );

查詢池數據源的當前狀態

c3p0數據源依賴着一個包括ComboPooledDataSource的實現和DataSources.pooledDataSource(...)方法返回對象,以及實現com.mchange.v2.c3p0.PooledDataSource全部接口的池。這使得有大量查詢數據源鏈接池狀態的方法可用。

查詢數據源狀態的實例代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// fetch a JNDI-bound DataSource
InitialContext ictx = new InitialContext();
DataSource ds = (DataSource) ictx.lookup( "java:comp/env/jdbc/myDataSource" );

// make sure it's a c3p0 PooledDataSource
if (ds instanceof PooledDataSource){
  PooledDataSource pds = (PooledDataSource) ds;
  System.err.println("num_connections:"+ pds.getNumConnectionsDefaultUser());
  System.err.println("num_busy_connections:"+pds.getNumBusyConnections
  DefaultUser());
  System.err.println("num_idle_connections:"+pds.getNumIdleConnections
  DefaultUser());
  System.err.println();
}
else
  System.err.println("Not a c3p0 PooledDataSource!");

這些狀態查詢方法有三種重載方式:

  • public int getNumConnectionsDefaultUser()
  • public int getNumConnections(String username, String password)
  • public int getNumConnectionsAllUsers()

清理c3p0 PooledDataSources

最簡單的清理c3p0 PooledDataSources的方法就是調用DataSources類的destory方法。只有PooledDataSource對象須要被清理。對非池化或非c3p0數據源調用DataSources.destory(...)方法也無妨。

1
2
3
4
5
6
7
8
9
10
11
DataSource ds_pooled = null;
try{
  DataSource ds_unpooled = DataSources.unpooledDataSource(
"jdbc:postgresql://localhost/testdb","swaldman","test-password");
  ds_pooled = DataSources.pooledDataSource( ds_unpooled );

  // do all kinds of stuff with that sweet pooled DataSource...
}
finally{
  DataSources.destroy( ds_pooled );
}

此外,你能夠經過調用c3p0的PooledDataSource接口的close()方法來關閉DataSource對象。所以,你能夠將DataSource對象轉換成PooledDataSource對象而後關閉它。

1
2
3
4
5
6
7
8
9
static void cleanup(DataSource ds) throws SQLException{
  // make sure it's a c3p0 PooledDataSource
  if ( ds instanceof PooledDataSource){
    PooledDataSource pds = (PooledDataSource) ds;
    pds.close();
  }     
  else
    System.err.println("Not a c3p0 PooledDataSource!");
}

ComboPooledDatasourcePooledDataSource的一個實例,也能直接被它的close()方法關閉。

在用戶調用close()方法而被關閉以前,未被引用的PooledDataSource實例不會被垃圾回收器調用finalize()而被關閉。自動銷燬機制和一般同樣,只是一種輔助方法,而不用來確保資源的清理。

建立我的的PoolBackedDataSource

你能夠經過這種方法來一步步地建立一個PoolBackedDataSource(對大多數程序員來講並沒必要要):

若是你的驅動提供了ConnectionPoolDataSource 的實現,你只須要:
實例化並配置一個非池化的DriverManagerDataSource,以後實例化一個WrapperConnectionPoolDataSource,將非池化的數據源設置爲它的nestedDataSource屬性,而後將它設定爲一個PoolBackedDataSource對象的connectionPoolDataSource屬性。

除了使用c3p0的WrapperConeectionPoolDataSource以外,你還能夠建立一個PollBackedDataSource,然 後 設 定 它 的connectionPoolDataSource屬 性。第三方的ConnectionPoolDataSource不支持Statement池ConnectionCustomizers,和一些特定的 c3p0屬性(第三方的 DataSource 實現能夠用來替代c3p0的DriverManagerDataSource,這在功能上並無什麼明顯的損失)。

原生鏈接(Raw Connection)和Statement操做

JDBC驅動在實現ConnectionStatement上有時定義了一些與特定廠商的,不標準的API。c3p0將這些對象包裝進了一個代理裏,因此你不能把c3p0返回的 Connection 或Statement 轉換成特定廠商的實現。c3p0沒有提供任何可以直接訪問原生鏈接和Statement的方法,這是由於c3p0須要一直按順序地追蹤Statement和結果集的建立,來防止資源緊缺和池訛誤(pool corruption)現象。

c3p0提供了一個能讓你經過反射在底層的鏈接上來執行非標準方法的API。使用方法是:
首先將返回的Connection轉 換 成 一 個C3P0ProxyConnection。而後調用rawConnectionOperation方法,而後提供一個你想要執行的 java.lang.reflect.Method對象做爲這個非標準方法的參數。你提供的這個Method對象將會在第二個參數(null或者靜態方法)上執行,而且使用你提供的第三個參數來完成這個方法。對目標對象和這個方法的全部參數來說,你均可以使用 C3P0ProxyConnection.RAW_CONNECTION這個特殊的標記,它將會在方法執行前替代底層的特定廠商的Connection

C3P0ProxyStatement也提供了相似的API。

原生操做返回的全部Statement(包括PreparedCallableStatement)和ResultSet都是被c3p0所管理的,因此在其父代理鏈接上調用close()方法的時候它們都會被正確地清理。用戶必須注意清理那些與特定廠商相關的方法返回的那些非標準的資源。

使用 Oracle特定的API在原生鏈接上調用靜態方法的例子:

1
2
3
4
C3P0ProxyConnection castCon = (C3P0ProxyConnection) c3p0DataSource.getConnection();
Method m = CLOB.class.getMethod("createTemporary", new Class[]{Connection.class, boolean.class, int.class});
Object[] args = new Object[] {C3P0ProxyConnection.RAW_CONNECTION, Boolean.valueOf( true ), new Integer( 10 )};
CLOB oracleCLOB = (CLOB) castCon.rawConnectionOperation(m, null, args);

C3P0 如今支持一些 Oracle 特定的方法了,在本文的其餘相關中有詳細的介紹。

屬性配置

c3p0沒有過多的必須(required)配置信息,它很是靈活可控。大多數的配置信息都是JavaBean屬性。下面就是 JavaBean 的慣例,若是有一個對象有一個類型爲 T 的屬性 foo,這個對象就會有相似這樣的方法…

  • public T getFoo();
  • public void setFoo(T foo);

這樣的方法是否成對存在,取決於這個屬性是隻可讀的,只可寫,仍是可讀寫的。

有多種方法修改 c3p0 的屬性:你能夠直接在代碼裏經過關聯一個特定的數據源來改變配置,你也能夠在外部經過簡單的Java屬性文件(simple Java properties file),XML配置文件或系統屬性來配置c3p0。一般來說,配置文件都被命名爲c3p0.propertiesc3p0-config.xml,並放置在應用的CLASSPATH的頂級路徑中,可是 XML 配置文件能夠被放在應用所在的文件系統的任何位置,你只須要改變 com.mchange.v2.c3p0.cfg.xml這個系統屬性便可(絕對路徑)。

數據源一般在使用以前被配置,好比在構造方法中配置或者在構造方法返回以後立刻進
行配置。不過 c3p0 也支持使用過程當中修改配置。

若是你經過調用工具類com.mchange.v2.c3p0.DataSources的工廠方法來獲取數據源,而且不但願這個數據源使用默認的配置,那麼你能夠提供一個Map類型的參數做爲配置信息[key必須是小寫字母開頭的屬性名,value能夠是字符串或者「被打包(boxed)」的Java原生類型,例如IntegerBoolean]。

全部可改變的屬性在附錄中都有詳細的文檔。

鏈接池基本配置

c3p0 鏈接池能夠經過下面幾個基本參數來簡單地配置:

  • acquireIncrement
  • initialPoolSize
  • maxPoolSize
  • maxIdleTime
  • minPoolSize

initialPoolSizeminPoolSizemaxPoolSize定義了由池管理的鏈接數量。請確保minPoolSize<=maxPoolSize。不合理的initialPoolSize值將會被忽略,而後使用 minPoolSize來替代。

minPoolSizemaxPoolSize的範圍以內,池中的鏈接數量與使用模式(usage patterns)有關。當用戶請求一個鏈接,池中又沒有可用鏈接,而且池中的鏈接數量還未達到maxPoolSize的時候,池中的鏈接數就會增加。由於獲取鏈接很是慢,因此成批地增長鏈接數量一般都頗有效,而不是強制要用戶在須要新鏈接時從頭開始激活並獲取一個鏈接。acquireIncrement屬性決定了c3p0在沒有可用鏈接時一次性獲取的新鏈接數量。(不過c3p0毫不會所以而使鏈接數超過maxPoolSize值。)

當鏈接池測試一個鏈接而且發現它已失效(broken)(參考下面的配置鏈接測試),或者當一個鏈接因空閒期超過一段時間而過時,或太舊(too old)(參考管理池尺寸和鏈接壽命)的時候,鏈接池中的鏈接數量將會降低。

容量和鏈接壽命配置

C3P0 提供了大量的選項來控制池內鏈接數的增加或減少的速度,也能夠用一些選項來決定「舊」鏈接是否應該主動地被替換以維持應用的可靠性。

  • maxConeectionAge
  • maxIdleTime
  • maxIdleTimeExcessConeections

默認狀況下,鏈接池不會給鏈接設定過時時間。若是你爲了保持鏈接「新鮮」,想要給
鏈接設定過時時間的話,須要設定 maxIdleTime 和/或 maxConnectionAgemaxIdleTime定義了鏈接因在多少秒內未被使用而被鏈接池剔除的時間。maxConnectionAge決定了全部從數據庫中獲取的鏈接將在多少秒後被鏈接池剔除。

maxIdleTimeExcessConnections用來最小化 c3p0 欠載(under load)時的鏈接數。默認狀況下,在 c3p0 欠載時,c3p0 只會因鏈接測試失敗或者鏈接過時而縮小池中的鏈接數。有一些用戶須要在一些忽然增大會鏈接數的操做以後快速地釋放沒必要要的鏈接。你能夠經過把maxIdleTimeExcessConnetions設定爲一個比 maxIdleTime小得多的值來達到這個目的。超過最小鏈接數的那些鏈接會在較小的一段空閒時間以後被鏈接池剔除。

對設置這類超時參數有一些普通的建議:悠着點!使用鏈接池的重點就是儘可能只從數據庫中獲取鏈接一次,而後不斷重複地使用它們。大多數的數據庫的鏈接能夠一次維持若干小時。沒有必要每隔幾秒鐘或幾分鐘就剔除那些空閒的鏈接。把maxConnectionAge 或maxIdleTime設置成 1800 (30 分鐘)都是有些激進的。對於大多數數據庫來說,幾個小時或許更加合理。你能夠用鏈接測試來確保可靠性,而不是一味地剔除它們(見配置鏈接測試)。一般只有 maxIdleTimeExcessConnetions這個參數能夠被設置成幾分鐘或更短的時間。

鏈接測試配置

c3p0 的鏈接測試能夠用來最小化你的應用遇到失效或過期的鏈接的可能性,它能夠用
多種方式來進行配置。池中的鏈接可能會由於各類緣由而變得不可用——有些 JDBC 驅動有意地對長鏈接設置了超時參數;後端的數據庫或網絡有時候會宕掉;有些鏈接僅僅是由於資源緊缺,驅動的漏洞或者其餘緣由而變得不可用。

c3p0 經過如下參數爲用戶提供了靈活的測試鏈接的方法:

  • automaticTestTable
  • connectionTesterClassName
  • idleConnectionTestPeriod
  • preferredTestQuery
  • testConnectionOnCheckin
  • testConnectionOnChechout

idleConnetionTestPeriodtestConnectionOnCheckouttestConnectionOnCheckin 決定了鏈接什麼時候被測試。automaticTestTable,connectionTesterClassName 和 preferredTestQuery決定了鏈接怎樣被測試。

當配置鏈接測試的時候,首先應該考慮如何減小測試的開支。默認狀況下,鏈接經過在
與其關聯的 DatabaseMetaData對象上調用 getTables()方法來進行測試。這對全部數據庫來說都有效,由於這與數據庫的視圖(database schema)無關。然而,從經驗上來說,調用DatabaseMetaData.getTables()方法相對於進行一個簡單的數據庫查詢要慢多了。

提升鏈接測試速度的最方便的方法就是定義 automaticTestTable 屬性。c3p0 將會使用你提供的名字建立一個空的表,而後經過一個簡單的查詢來測試數據庫。你也能夠經過設定preferredTestQuery參數來定義一個測試語句。不過你得小心點,設置 preferredTestQuery 將會致使在初始化數據源以前出現錯誤,若是你查詢的目標表不存在的話。

高級用戶能夠實現一個 ConnectionTester然 後 提 供 一 個 類 的 全 限 定 名 做 爲connectionTesterClassName 屬 性 來 實 現 任 何 想 要 的 連 接 測 試 。 如 果 你 想 要 使 你 的ConnectionTester 能 夠 支 持 preferredTestQueryautomaticTestTable 屬 性 , 實 現UnifiedConnectionTester接口便可,實現AbstractConnectionTester是最方便的。更多信息見API 文檔。

檢測鏈接最可靠的時間就是從池中取出鏈接的時候(check-out)。但從客戶端性能的角度 來 看 , 是 這 也 是 開 銷 最 大 的 。 大 多 數 應 用 將 idleConnectionTestPeriodtestConnectionOnCheckIn結合起來用就已經很是可靠了。空閒測試和將鏈接放回池時(check-in)的測試都是異步執行的,這就是爲何它們有更好的性能的緣由。

注意,對有些應用程序來講,擁有高性能遠比避免偶然發生的數據庫異常更重要。默認
狀況下,c3p0 不會作任何鏈接測試。設置一個很是長的idleConnectionTestPeriod值和避免check-out 與 check-out 測試是很不錯的,高性能的方法。

Statement池配置

c3p0 實現了符合 JDBC 規範的透明的 PreparedStatement池。在一些狀況下,Statement池可以顯著地提升應用程序的性能。但在另外一些狀況下,Statement池的開銷又會稍微的下降性能。

statement到底能不能改善性能或者可以改善多少性能仍是取決於你的數據庫對查詢的解析,規劃和優化(parsing, planning , and optimizing)。不一樣數據庫(和 JDBC 驅動)之間在這個方面存在很大的差別。給你的應用程序在使用和不使用statement池的時候設定基準,而後比較它們來看看究竟statement能不能改善性能是個不錯的點子。

你能夠經過設置下面的配置參數來配置 statement池:

  • maxStatement
  • maxStatementPerConnection

maxStatement 是 JDBC 規範的標準參數。maxStatement定義了每一個數據源會緩存的PreparedStatement 的總數。池內的Statement 總數在達到這個限制時會銷燬那些最近最近最少使用的(least-recently-used)Statement。這聽起來很簡單,不過事實上有些奇怪,由於從概念上來說,被緩存的 Statement是屬於單個的數據庫鏈接的,它們並非全局資源。爲了弄清楚maxStatements 的大小,你不該該簡單地認爲它就是池中 statement的數量,你應該將你的應用程序中的最經常使用的PreparedStatement的數量乘以合理的鏈接數(好比在一個高負荷的應用中的 maxPoolSize值)。

maxStatementsPerConnection 不是一個標準的配置參數,這可能會使你感受有些不天然。它定義了鏈接池中每一個鏈接最多能擁有(緩存)多少 Statement。爲了不過多的折騰,你能夠把這個值設爲稍大於你應用中的 PreparedStatements 數量的一個數字。

這兩個值中的任何一個大於 0 的話, statement 池就會被開啓。若是兩個參數都大於 0,它們的限制都會被強制執行。若是隻有一個參數大於 0,僅僅只有一個限制會被強制執行。

數據庫故障修復配置

c3p0 被設計成(而且默認開啓了)能夠從臨時的數據庫故障中恢復,好比數據庫重啓或者短暫地斷開網絡。你能夠經過如下幾個屬性改變對 c3p0 在獲取鏈接時遇到的錯誤的處理方式:

  • acquireRetryAttempts
  • acquireRetryDelay
  • breakAfterAcquireFailure

當 c3p0 在嘗試獲取數據庫鏈接失敗時,會自動地重試 acquireRetryAttempts次,每次間隔 acquireRetryDelay。若是依然失敗,全部在等待這些鏈接的客戶端將會收到一個異常,用來表示不能獲取鏈接。請注意,若是不是全部的獲取鏈接嘗試都失敗,客戶端並不會收到異常,這可能在初始化嘗試獲取鏈接以後還須要一點兒時間。若是acquireRetryAttempts 被設置爲0,c3p0將會無限期地嘗試獲取一個新的鏈接,對 getConnection()的調用可能會無限阻塞下去,直到成功獲取一個鏈接。

一旦全部的獲取鏈接的嘗試都失敗,有兩種可能的處理方式。默認狀況下,c3p0 數據源會保持活性,而後對後續的請求做出迴應。若是你將 breakAfterAcquireFailure 設置爲 true的話,數據源將會在全部嘗試失敗後立刻中止工做,而且後續的請求也會立刻失敗。

請注意,若是數據庫重啓了,一個鏈接池也許還維持着那些之前獲取的而如今變得不可用的鏈接。默認狀況下,這些陳舊的鏈接不會被立刻發現而且清理掉,當一個應用程序使用它們的時候,會立刻獲得一個異常。設定 maxIdleTime 或者maxConnectionAge 能夠幫助你加速替換掉這些不可用的鏈接。(見鏈接壽命的管理)若是你想徹底避免應用程序所以遇到異常,你必須得指定一中鏈接測試策略用來在客戶端使用不可用鏈接以前就清理掉它們。(見鏈接測試的配置)即便使用積極的鏈接測試(testConnectionsOnCheckout設置爲true,或者testConnectionsOnCheckintrue而且設置了一個小的 idleConnectionTestPeriod值),你的應用程序在數據庫重啓的時候依然有可能遇到一個相關的異常,好比數據庫在你已經將鏈接測試成功後才重啓。

使用連接定製器管理鏈接生命週期

應用程序在獲取鏈接後常常會但願可以以某些標準的方法來重複地使用這些鏈接。例如,經過特定廠商的 APIs 或不標準的 SQL 擴展來設定字符編碼或者日期時間等行爲。有時候重寫標準的鏈接中的默認屬性值是頗有用的,好比重寫 transactionIsolationholdbility或者readOnly。 c3p0 提供了一個「鉤子」接口,你實現它就有機會在剛剛從數據庫得到鏈接以後,在鏈接被送至客戶端以前,在鏈接返回鏈接池以前,在鏈接最終被鏈接池淘汰以前,修改或追蹤這個鏈接。交給ConnectionCustomizer 的鏈接是原生的,它全部的特定廠商的 API 均可以被訪問。

ConnectionCustomizer類的更多信息見 API 文檔。

安裝 ConnectionCustomizer 的方法就是實現這個接口,讓其對 c3p0 的類加載器課件,而後設置下面這個配置屬性:

  • connectionCustomizerClassName

ConnectionCustomizer必須是不可變類,而且擁有一個沒有參數的公開的構造方法。它不該該保存任何狀態。(不多)有一些應用程序但願使用 ConnectionCustomizer 來追蹤單個的數據源的行爲,這些與生命週期有關的方法都能接受一個特定的數據源的「實體令牌(identityToken)」做爲參數,每一個 PooledDataSource 的實體令牌都是惟一的。

下面是一個簡單的 ConnectionCustomizer。實現類沒有必要重寫 ConnectionCustomizer 接口中的全部的四個方法,只須要繼承 AbstractConnectionCustomizer 類就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import com.mchange.v2.c3p0.*;
import java.sql.Connection;

public class VerboseConnectionCustomizer{
    public void onAcquire( Connection c, String pdsIdt ){ 
        System.err.println("Acquired " + c + " [" + pdsIdt + "]"); 

        // override the default transaction isolation of 
        // newly acquired Connections
        c.setTransactionIsolation( Connection.REPEATABLE_READ );
    }

    public void onDestroy( Connection c, String pdsIdt ){ 
        System.err.println("Destroying " + c + " [" + pdsIdt + "]"); 
    }

    public void onCheckOut( Connection c, String pdsIdt ){ 
        System.err.println("Checked out " + c + " [" + pdsIdt + "]"); 
    }

    public void onCheckIn( Connection c, String pdsIdt ){ 
        System.err.println("Checking in " + c + " [" + pdsIdt + "]"); 
    }
}

未結束事務處理方式配置

鏈接池中被檢查過的鏈接不能有任何未結束的事務與其相關聯。若是用戶把一個鏈接的
autoCommit屬性設置成 false,而且 c3p0 不能保證在這個鏈接上沒有後續的事務工做的話,c3p0 就會在 check-in (當用戶調用close()方法)的時候調用rollback()方法或者 commit()方法。

JDBC 在有未結束事務的鏈接關閉時是應該回滾事務仍是應該提交事務這個問題上保持了沉默(這簡直不可原諒)。在默認狀況下,c3p0 會當用戶在有未結束事務的鏈接上調用 close()方法時回滾事務。

你能夠經過下面的配置參數更改這些相關行爲:

  • autoCommitOnClose
  • foreIgnoreUnresolvedTransactions

若是你想要 c3p0 在鏈接返回鏈接池時(checkin )提交未結束的事務,只須要把
autoCommitOnClose 設置爲 true。若是你但願本身管理這些未結束的事務的話(而且沒有設置鏈接的 autoCommit 屬性), 你能夠把forceIgnoreUnresolvedTransactions 設置爲 true。咱們強烈地不鼓勵設置 forceIgnoreUnresolvedTransactions 的值,由於若是客戶端在鏈接關閉前即沒有回滾也沒有提交事務,而且也沒有開啓自動提交的話,一些奇怪的不可再生的行爲(unreproduceable behavior)和數據庫被鎖住的現象會發生。

調試和解決問題客戶端應用配置

有時候客戶端應用程序對關閉鏈接這種工做很馬虎。因而最後池內鏈接數增加到了maxPoolSize,而後就用盡了全部鏈接,這種結果是這些有問題得客戶端形成的。解決這個問題的正確的方法就是修復這些客戶端程序。c3p0 能夠幫助你找到那些偶爾不能正確地返回鏈接池的鏈接。在一些極少見而且不幸的狀況下,即便你關閉了有漏洞的應用程序,你也修復不了它。c3p0 可以幫你解決這些問題。

下面的幾個參數能夠幫助你調試和解決有問題得客戶端程序。

  • debugUnreturnedConnectionsStackTraces
  • unreturnedConnectionTimout

unreturnedConnectionTimeout 決定了從池中取出的鏈接能維持多少秒。 若是這個值非零,那麼從池中取出的那些在超過這個限制時間的鏈接尚未返回池得話,就會被馬上銷燬,而後在池中被替代。很顯然,你必需要保證這個參數的值可以讓鏈接有時間完成那些應該作的工做。你能夠用這個參數來解決那些關閉鏈接失敗的不可靠的客戶端程序。

完 全 修 復 漏 洞 要 比 僅 僅 使 應 用 恢 復 正 常 工 做 要 好 得 多 。 除 了 設 置 了unreturnedConnectionTimeout 以外,若是你還把 debugUnreturnedConnectionStackTraces 設置爲true的話,你將能夠獲得那些從池中取出的鏈接的軌跡棧(stack trace)。當有鏈接沒有按時返回池的時候,軌跡棧將會被打印出來,來揭示哪裏有鏈接沒有按時返回。

避免客戶熱重部署中的內存泄露配置

c3p0引發了許多線程(helper threads,java.util.Timer.threads),並遲於應答池數據源的首次客戶請求。默認狀況下,c3p0引起的線程從這個第一次調用的線程中繼承了java.security.AccessControlContext和contextClassLoader的特性。若是該線程來自某個須要熱取消部署的客戶端,這些引用可能會被劃分爲一個ClassLoader以避免被垃圾回收而終止取消部署程序。

c3p0提供了兩個相關的參數:

  • contextClassLoaderSource
    • privilegeSpawnedThreads

contextClassLoaderSource應當設置一個caller或library或爲空。(默認是一個caller)若是使用c3p0的ClassLoader將它設置爲一個library,那麼須要重部署的客戶端將再也不包含引用。

privilegeSpawndThreads是一個默認爲false的布爾值。若將它設置爲true,那麼c3p0的線程將使用c3p0庫中的AccessControlContext,而不是可能和客戶端程序相關聯從而阻止垃圾回收的 AccessControlContext。

其餘數據源配置

在附錄中查看如下幾個配置參數的更多信息:

  • checkoutTimeout
  • factoryClassLocation
  • maxAdminisrativeTaskTime
  • numHelperThreads
  • usesTraditionalReflectiveProxies

numHelperThreads 和 maxAdministrativeTaskTime幫助你配置數據源線程池的行爲。默認狀況下,每一個數據源僅有三個助手線程(helper threads)。若是性能看起來被高負荷工做拖慢,或者你經過 JMX 觀察到或直接檢測出了「附加任務(pending tasks)」數量超過了0 的話,把numHelperThreads 的值提升試試吧。

maxAdministrativeTaskTime 可能對那些面臨無限掛起的任務或者出現明顯的死鎖信息的用戶有幫助。(更多信息見附錄)

若是全部的鏈接都從池中取了出去,客戶端不能當即獲得鏈接的話,checkoutTimeout限制了客戶端會爲獲得一個鏈接等待多久。usesTraditionalReflectiveProxies 這個參數不多用到,它將容許你使用一種陳舊的,如今已經被取代的由 C3P0 生成的代理對象。(C3P0 之前使用反射和動態代理,而如今爲了提高性能,使用了字節碼生成,非反射的實現。 )若是客戶端沒有在本地安裝 c3p0,而且 c3p0 的數據源是以一種引用的形式從 JNDI 裏獲得的,factoryClassLocation就能用來甄別 c3p0 的哪些類是能夠被下載下來的。

經過JMX配置和管理c3p0配置

若是在你的環境中有 JMX 類庫和 JMX MbeanServer(它們在 JDK 1.5 以上版本已經被包括了進去),你能夠經過 JMX 管理工具(好比 JDK 1.5 內置的 jconsole)來檢測和配置 c3p0。你會發現 c3p0 在 com.mchange.v2.c3p0下注冊了不少 MBean,有一個MBean是整個庫的彙總(叫作 C3P0Registry),每一個你部署的 PooledDataSource 也對應着一個MBean。你能夠經過這個 PooledDataSource 的MBean來查看或者修改你的配置信息,追蹤鏈接、Statement、線程池和其餘的池與數據源的活動。(你可能須要查看 PoolDataSource 的 API 文檔來獲取它的可用的操做。)

c3p0中名爲PooledDataSourcesmbeans將會連同dataSourceName屬性一同註冊。若是你配置了這個屬性,能夠確保語義等價的數據源在程序重啓時是可分辨的。

若是你但願從單個MBean server中監控多個c3p0設施,你能夠自定義JMX中出現的C3P0Registry下的名稱。你能夠c3p0.properties配置文件或HOCON config中這樣來配置系統文件:

1
com.mchange.v2.c3p0.management.RegistryName=myRegistryName

若是你不須要 c3p0 在你的 JMX 環境下注冊 MBean ,你能夠c3p0.properties 配置文件或HOCON config中這樣來配置系統文件:

1
com.mchange.v2.c3p0.management.ManagementCoordinator=com.mchange.v2.c3p0.management.NullManagementCoordinator

日誌配置

c3p0 使用了一種與 jakarta commons-logging 很類似的日誌類庫。日誌信息能夠傳給流行的日誌類庫 log4j, JDK 1.4 中推薦的標準日誌設備或者 System.err。差很少全部的配置均可以在你喜歡的那些高層的日誌類庫中完成。只有少數幾個配置是 c3p0 的日誌所特有的,而且使用默認配置就好了。和日誌相關的配置參數可能在你的c3p0.properties文件裏,或者在你CLASSPATH的頂級目錄中的 mchange-log.properties 文件裏,也有可能在系統屬性裏定義。(下面的日誌配置參數可能不能在 c3p0-config.xml 中定義!)。見下面的文本框。

c3p0 的日誌行爲會被一些編譯期選項(build-time options)影響。若是編譯期選項c3p0.debug 被設置成 false,全部低於INFO級別的日誌信息將會被忽略。編譯期選項 c3p0.trace可以控制低於 INFO 級別的日誌信息的報告顆粒細度。目前來說,c3p0 的發行版本的二進制文件都是把 debug 設置成true,把 trace 設置成最大值 10 來進行編譯的。不過最終可能會在發行版中把 debug設置爲 false。[就目前來說,日誌級別檢查(logging level-checks)對性能的影響是很小的, 編譯期間對這些信息的控制都至關靈活,你也可以讓你的日誌類庫來控制哪些信息是要被記錄的。]當 c3p0 啓動的時候,那些 debug 和 trace 的編譯期的值也會隨着版本和編譯時間被記錄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
com.mchange.v2.log.MLog
Determines which library c3p0 will output log messages to. By default, if log4j is available,
it will use that library, otherwise if jdk1.4 logging apis are available it will use those, 
and if neither are available, it will use a simple fallback that logs to System.err. 
If you want to directly control which library is used, you may set this property to one of:
        com.mchange.v2.log.log4j.Log4jMLog
        com.mchange.v2.log.slf4j.Slf4jMLog
        com.mchange.v2.log.jdk14logging.Jdk14MLog
        com.mchange.v2.log.FallbackMLog
    Alternatively, the following abbreviations are supported:
        log4j
        slf4j
        jul, jdk14, java.util.logging
        fallback
    You may also set this property to a comma separated list of any mix the above alternatives, 
    to define an order of preference among logging libraries.
com.mchange.v2.log.jdk14logging.suppressStackWalk
Under JDK standard logging, the logging library may inspect stack traces to determine the 
class and method from which a log message was generated. That can be helpful, but it is also 
slow. Setting this configuration parameter to true will suppress this stack walk, and reduce 
the overhead of logging. This property now defaults to true, and logger names are logged in 
place of class names. To return to the original slower but more informative approach, explicitly 
set the property to false.
com.mchange.v2.log.NameTransformer
By default, c3p0 uses very fine-grained logging, in general with one logger for each c3p0 
class. For a variety of reasons, some users may prefer fewer, more global loggers. You may 
opt for one-logger-per-package by setting com.mchange.v2.log.NameTransformer to the value 
com.mchange.v2.log.PackageNames. Advanced users can also define other strategies for 
organizing the number and names of loggers by setting this variable to the fully-qualified 
class name of a custom implementation of the com.mchange.v2.log.NameTransformer interface.
com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL
If, whether by choice or by necessity, you are using c3p0's System.err fallback logger, you 
can use this parameter to control how detailed c3p0's logging should be. Any of the following 
values (taken from the jdk1.4 logging library) are acceptable:
        OFF
        SEVERE
        WARNING
        INFO
        CONFIG
        FINE
        FINER
        FINEST
        ALL
    This property defaults to INFO.

命名配置

你能夠定義命名配置以擴充和重寫定義的默認配置。當你實例化一個c3p0池化數據源時,不管是經過ComboPooledDataSource構造器仍是經過DataSources工廠類構造,你均可以替換它的名字。例如:
經過ComboPooledDataSource

1
ComboPooledDataSource cpds = new ComboPooledDataSource("intergalactoApp");

經過DataSources工廠類:

1
DataSource ds_pooled = DataSources.pooledDataSource( ds_unpooled, "intergalactoApp" );

你能夠這樣定義命名配置:
在屬性類型的配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
# define default-config param values
c3p0.maxPoolSize=30
c3p0.minPoolSize=10

# define params for a named config called intergalactoApp
c3p0.named-configs.intergalactoApp.maxPoolSize=1000
c3p0.named-configs.intergalactoApp.minPoolSize=100
c3p0.named-configs.intergalactoApp.numHelperThreads=50

# define params for a named config called littleTeenyApp
c3p0.named-configs.littleTeenyApp.maxPoolSize=5
c3p0.named-configs.littleTeenyApp.minPoolSize=2

在HOCON配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
c3p0 {
    maxPoolSize=30
    minPoolSize=10

    named-configs {
        intergalactoApp {
            maxPoolSize=1000
            minPoolSize=100
            numHelperThreads=50
        }
        littleTeenyApp {
            maxPoolSize=5
            minPoolSize=2
        }
    }
}

在XML配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<c3p0-config>

    <default-config>
        <property name="maxPoolSize">30</property>
        <property name="minPoolSize">10</property>
    </default-config>

    <named-config name="intergalactoApp">
        <property name="maxPoolSize">1000</property>
        <property name="minPoolSize">100</property>
        <property name="numHelperThreads">50</property>
    </named-config>

    <named-config name="littleTeenyApp">
        <property name="maxPoolSize">5</property>
        <property name="minPoolSize">2</property>
    </named-config>

</c3p0-config>

各用戶(Per-user)配置

你能夠爲某個特定用戶已驗證的池鏈接定義默認或命名配置的重寫方法。並不是全部的配置參數都支持各用戶的方法重寫。詳情可見附錄。

你能夠這樣定義各用戶配置:
在屬性類型的配置文件中:

1
2
3
4
5
6
7
8
9
10
11
# define default-config param values
c3p0.maxPoolSize=30
c3p0.minPoolSize=10

# define params for a user called 'steve'
c3p0.user-overrides.steve.maxPoolSize=15
c3p0.user-overrides.steve.minPoolSize=5

# define params for a user called 'ramona'
c3p0.user-overrides.steve.maxPoolSize=50
c3p0.user-overrides.steve.minPoolSize=20

在HOCON配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
c3p0 {
    maxPoolSize=30
    minPoolSize=10

    user-overrides {
        steve {
            maxPoolSize=15
            minPoolSize=5
        }
        ramona {
            maxPoolSize=50
            minPoolSize=20
        }
    }
}

在XML配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<c3p0-config>

    <default-config>

        <property name="maxPoolSize">30</property>
        <property name="minPoolSize">10</property>

        <user-overrides user="steve">
            <property name="maxPoolSize">15</property>
            <property name="minPoolSize">5</property>
        </user-overrides>

        <user-overrides user="ramona">
            <property name="maxPoolSize">50</property>
            <property name="minPoolSize">20</property>
        </user-overrides>

    </default-config>

</c3p0-config>

用戶配置擴展

用戶能夠添加自定義的配置信息,一般是定製的ConnectionCustomizers行爲。用戶自定義的配置存儲爲一個包含了String鍵和值的Map,存儲在如下配置參數中:

  • extensions

這個擴展Map能像其餘的配置參數同樣經過編程來配置。不過,定義這個擴展Map的鍵和值有着特殊的配置文件支持:
在屬性類型的配置文件中:

1
2
3
c3p0.extensions.initSql=SET SCHEMA 'foo'
c3p0.extensions.timezone=PDT
...

在HOCON配置文件中:

1
2
3
4
5
6
c3p0 {
    extensions {
        initSql=SET SCHEMA 'foo'
        timezone=PDT
    }
}

在XML配置文件中:

1
2
3
4
5
6
7
8
<c3p0-config>
    <default-config>
        <extensions>
            <property name="initSql">SET SCHEMA 'foo'</property>
            <property name="timezone">PDT</property>
        </extensions>
    </default-config>
</c3p0-config>

爲了找到池化數據源的擴展定義,你必須得到它的identityToken權限,這在全部ConnectionCustomizer中都做爲一個參數被提供。得到了identityToken權限,你就能夠經過使用C3P0Registry.extensionsForToken(...)方法來獲取擴展Map

因爲這些擴展主要被設計用於ConnectionCustomizer的實現,AbatractConnectionCustomizer類一樣定義了一個protected extensionForToken(...)方法。

下面是一個使用了用戶自定義配置擴展的ConnectionCustomizer實現。它定義了一個initSql擴展,這個擴展的值應當是String類型的包含應當在Connection被池容許時執行的SQL語句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package mypkg;

import java.sql.*;
import com.mchange.v2.c3p0.AbstractConnectionCustomizer;

public class InitSqlConnectionCustomizer extends AbstractConnectionCustomizer{
    private String getInitSql( String parentDataSourceIdentityToken ){
    return (String) extensionsForToken( parentDataSourceIdentityToken ).get ( "initSql" ); 
}

    public void onCheckOut( Connection c, String parentDataSourceIdentityToken) throws Exception{
        String initSql = getInitSql( parentDataSourceIdentityToken );
        if ( initSql != null ){
            Statement stmt = null;
            try{
                stmt = c.createStatement();
                stmt.executeUpdate( initSql );
            }
            finally{ 
                if ( stmt != null ) stmt.close(); 
            }
        }
    }
}

混合命名的、各用戶的、用戶定義的配置擴展

命名配置、各用戶重寫以及用戶自定義配置擴展能夠很方便地結合起來:
在屬性類型的配置文件中:

1
2
3
4
5
6
c3p0.maxPoolSize=30
c3p0.extensions.initSql=SET SCHEMA 'default'

c3p0.named-configs.intergalactoApp.maxPoolSize=1000
c3p0.named-configs.intergalactoApp.extensions.initSql=SET SCHEMA 'intergalacto'
c3p0.named-configs.user-overrides.steve.maxPoolSize=20

在HOCON配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
c3p0 {
    maxPoolSize=30
    extensions {
        initSql=SET SCHEMA 'default'
    }
    named-configs {
        intergalactoApp {
            maxPoolSize=1000
            user-overrides {
                steve {
                    maxPoolSize=20
                }
            }
            extensions {
                initSql=SET SCHEMA 'intergalacto'
            }
        }
    }
}

在XML配置文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<c3p0-config>

    <default-config>
        <property name="maxPoolSize">30</property>
        <extensions>
            <property name="initSql">SET SCHEMA 'default'</property>
        </extensions>
    </default-config>

    <named-config name="intergalactoApp">
        <property name="maxPoolSize">1000</property>
        <user-overrides name="steve">
            <property name="maxPoolSize">20</property>
        </user-overrides>
        <extensions>
            <property name="initSql">SET SCHEMA 'intergalacto'</property>
        </extensions>
    </named-config>

</c3p0-config>

附錄

性能

加強性能,是鏈接池、 Statement 池以及 c3p0 類庫的主要目的。對大多數應用程序來講,鏈接池會使得性能顯著提升,特別是當你給每一個客戶端訪問每次都從新獲取鏈接的話。 若是你讓單個的共享的鏈接來爲多個客戶端服務以免過多的鏈接獲取工做的話,那麼你在多線程的環境下可能會遇到性能或者事物管理問題;鏈接池將會可以讓你有機會選擇不多或沒有開銷的單客戶端單鏈接模型(One Connection-per client model)。 若是你正在編寫企業級 Java Bean,你可能會想要只獲取一次鏈接而後並不返回它,直到它被銷燬或者過期。 可是這樣作太耗費資源了,由於這些 Bean 沒必要要的佔用了鏈接網絡和數據庫資源。鏈接池容許 Bean只在使用鏈接時才佔有鏈接。

可是,c3p0 也有性能上的開銷。爲了實現當父資源返回池得時候自動清理未被關閉的
ResultSet 和 Statement,全部客戶端可見的 ConnectionResultSetStatement都封裝了那些底層的數據源或者「傳統的」JDBC 驅動。所以,全部 JDBC 調用都會有一些額外的開銷。

c3p0 在減少「封裝」所帶來的性能開銷方面下了一些工夫。在個人環境中,由包裝所帶來的性能問題來自成百上千的數據庫獲取操做。因此,你應該從 c3p0 中獲得的是性能的提高和高效的資源利用,除非你快速地輪載(succession)了不少不少 JDBC 調用。很顯然,與結果集相關操做(好比要在其上遍歷一個有上千條記錄的表)帶來的開銷是能夠忽略不計的。

API

API文檔見:
http://www.mchange.com/projects/c3p0/apidocs/index.html

配置屬性和配置文檔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<c3p0-config>
<default-config>
<!--當鏈接池中的鏈接耗盡的時候c3p0一次同時獲取的鏈接數。Default: 3 -->
<property name="acquireIncrement">3</property>

<!--定義在從數據庫獲取新鏈接失敗後重復嘗試的次數。Default: 30 -->
<property name="acquireRetryAttempts">30</property>

<!--兩次鏈接中間隔時間,單位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>

<!--鏈接關閉時默認將全部未提交的操做回滾。Default: false -->
<property name="autoCommitOnClose">false</property>

<!--c3p0將建一張名爲Test的空表,並使用其自帶的查詢語句進行測試。若是定義了這個參數那麼
屬性preferredTestQuery將被忽略。你不能在這張Test表上進行任何操做,它將只供c3p0測試
使用。Default: null-->
<property name="automaticTestTable">Test</property>

<!--獲取鏈接失敗將會引發全部等待鏈接池來獲取鏈接的線程拋出異常。可是數據源仍有效
保留,並在下次調用getConnection()的時候繼續嘗試獲取鏈接。若是設爲true,那麼在嘗試
獲取鏈接失敗後該數據源將申明已斷開並永久關閉。Default: false-->
<property name="breakAfterAcquireFailure">false</property>

<!--當鏈接池用完時客戶端調用getConnection()後等待獲取新鏈接的時間,超時後將拋出
SQLException,如設爲0則無限期等待。單位毫秒。Default: 0 -->
<property name="checkoutTimeout">100</property>

<!--經過實現ConnectionTester或QueryConnectionTester的類來測試鏈接。類名需制定全路徑。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name="connectionTesterClassName"></property>

<!--指定c3p0 libraries的路徑,若是(一般都是這樣)在本地便可得到那麼無需設置,默認null便可
Default: null-->
<property name="factoryClassLocation">null</property>

<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文檔原文)做者強烈建議不使用的一個屬性-->
<property name="forceIgnoreUnresolvedTransactions">false</property>

<!--每60秒檢查全部鏈接池中的空閒鏈接。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>

<!--初始化時獲取三個鏈接,取值應在minPoolSize與maxPoolSize之間。Default: 3 -->
<property name="initialPoolSize">3</property>

<!--最大空閒時間,60秒內未使用則鏈接被丟棄。若爲0則永不丟棄。Default: 0 -->
<property name="maxIdleTime">60</property>

<!--鏈接池中保留的最大鏈接數。Default: 15 -->
<property name="maxPoolSize">15</property>

<!--JDBC的標準參數,用以控制數據源內加載的PreparedStatements數量。但因爲預緩存的statements
屬於單個connection而不是整個鏈接池。因此設置這個參數須要考慮到多方面的因素。
若是maxStatements與maxStatementsPerConnection均爲0,則緩存被關閉。Default: 0-->
<property name="maxStatements">100</property>

<!--maxStatementsPerConnection定義了鏈接池內單個鏈接所擁有的最大緩存statements數。Default: 0 -->
<property name="maxStatementsPerConnection"></property>

<!--c3p0是異步操做的,緩慢的JDBC操做經過幫助進程完成。擴展這些操做能夠有效的提高性能
經過多線程實現多個操做同時被執行。Default: 3-->
<property name="numHelperThreads">3</property>

<!--當用戶調用getConnection()時使root用戶成爲去獲取鏈接的用戶。主要用於鏈接池鏈接非c3p0
的數據源時。Default: null-->
<property name="overrideDefaultUser">root</property>

<!--與overrideDefaultUser參數對應使用的一個參數。Default: null-->
<property name="overrideDefaultPassword">password</property>

<!--密碼。Default: null-->
<property name="password"></property>

<!--定義全部鏈接測試都執行的測試語句。在使用鏈接測試的狀況下這個一顯著提升測試速度。注意:
測試的表必須在初始數據源的時候就存在。Default: null-->
<property name="preferredTestQuery">select id from test where id=1</property>

<!--用戶修改系統配置參數執行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">300</property>

<!--因性能消耗大請只在須要的時候使用它。若是設爲true那麼在每一個connection提交的
時候都將校驗其有效性。建議使用idleConnectionTestPeriod或automaticTestTable
等方法來提高鏈接測試的性能。Default: false -->
<property name="testConnectionOnCheckout">false</property>

<!--若是設爲true那麼在取得鏈接的同時將校驗鏈接的有效性。Default: false -->
<property name="testConnectionOnCheckin">true</property>

<!--用戶名。Default: null-->
<property name="user">root</property>

<!--早期的c3p0版本對JDBC接口採用動態反射代理。在早期版本用途普遍的狀況下這個參數
容許用戶恢復到動態反射代理以解決不穩定的故障。最新的非反射代理更快而且已經開始
普遍的被使用,因此這個參數未必有用。如今原先的動態反射與新的非反射代理同時受到
支持,但從此可能的版本可能不支持動態反射代理。Default: false-->
<property name="usesTraditionalReflectiveProxies">false</property>

<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">25</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">0</property>
<user-overrides user="swaldman">
</user-overrides>
</default-config>
<named-config name="dumbTestConfig">
<property name="maxStatements">200</property>
<user-overrides user="poop">
<property name="maxStatements">300</property>
</user-overrides>
</named-config>
</c3p0-config>

Hibernate相關

Hibernate的C3P0ConnectionPtovider重命名了7個c3p0配置屬性,若是你在Hibernate中設置了它們,將覆蓋全部可能在c3p0.properties文件中的配置。

c3p0本地屬性名 Hibernate配置鍵
c3p0.acquireIncrement hibernate.c3p0.acquire_increment
c3p0.idleConnectionTestPeriod hibernate.c3p0.idle_test_period
c3p0.initialPoolSize 未提供,使用最小值
c3p0.maxIdleTime hibernate.c3p0.timeout
c3p0.maxPoolSize hibernate.c3p0.max_size
c3p0.maxStatements hibernate.c3p0.max_statements
c3p0.minPoolSize hibernate.c3p0.min_size
c3p0.testConnectionOnCheckout hibernate.c3p0.validate(僅用於Hibernate 2.x)

你能夠在Hibernate配置中使用hibernate.c3p0前綴來設置任何c3p0屬性。例如:

1
2
hibernate.c3p0.unreturnedConnectionTimeout=30
hibernate.c3p0.debugUnreturnedConnectionStackTraces=true

JBoss相關

在JBoss中使用c3p0:

  1. 將c3p0的jar文件放到JBoss服務實例中的lib目錄下(如:${JBOSS_HOME}/server/default/lib
  2. 在JBoss服務實例的deploy目錄下(如:${JBOSS_HOME}/server/default/deploy)定義並保存c3p0-service.xml文件。參數必須大寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE server>

<server>

   <mbean code="com.mchange.v2.c3p0.jboss.C3P0PooledDataSource"
          name="jboss:service=C3P0PooledDataSource">
     
      <attribute name="JndiName">java:PooledDS</attribute>
      <attribute name="JdbcUrl">jdbc:postgresql://localhost/c3p0-test</attribute>
      <attribute name="DriverClass">org.postgresql.Driver</attribute>
      <attribute name="User">swaldman</attribute>
      <attribute name="Password">test</attribute>

      <!-- Uncomment and set any of the optional parameters below -->
      <!-- See c3p0's docs for more info.                         -->

      <!-- <attribute name="AcquireIncrement">3</attribute>                         -->
      <!-- <attribute name="AcquireRetryAttempts">30</attribute>                    -->
      <!-- <attribute name="AcquireRetryDelay">1000</attribute>                     -->
      <!-- <attribute name="AutoCommitOnClose">false</attribute>                    -->
      <!-- <attribute name="AutomaticTestTable"></attribute>                        -->
      <!-- <attribute name="BreakAfterAcquireFailure">false</attribute>             -->
      <!-- <attribute name="CheckoutTimeout">0</attribute>                          -->
      <!-- <attribute name="ConnectionCustomizerClassName"></attribute>             -->
      <!-- <attribute name="ConnectionTesterClassName"></attribute>                 -->
      <!-- <attribute name="Description">A pooled c3p0 DataSource</attribute>       -->
      <!-- <attribute name="DebugUnreturnedConnectionStackTraces">false</attribute> -->
      <!-- <attribute name="FactoryClassLocation"></attribute>                      -->
      <!-- <attribute name="ForceIgnoreUnresolvedTransactions">false</attribute>    -->
      <!-- <attribute name="IdleConnectionTestPeriod">0</attribute>                 -->
      <!-- <attribute name="InitialPoolSize">3</attribute>                          -->
      <!-- <attribute name="MaxAdministrativeTaskTime">0</attribute>                -->
      <!-- <attribute name="MaxConnectionAge">0</attribute>                         -->
      <!-- <attribute name="MaxIdleTime">0</attribute>                              -->
      <!-- <attribute name="MaxIdleTimeExcessConnections">0</attribute>             -->
      <!-- <attribute name="MaxPoolSize">15</attribute>                             -->
      <!-- <attribute name="MaxStatements">0</attribute>                            -->
      <!-- <attribute name="MaxStatementsPerConnection">0</attribute>               -->
      <!-- <attribute name="MinPoolSize">0</attribute>                              -->
      <!-- <attribute name="NumHelperThreads">3</attribute>                         -->
      <!-- <attribute name="PreferredTestQuery"></attribute>                        -->
      <!-- <attribute name="TestConnectionOnCheckin">false</attribute>              -->
      <!-- <attribute name="TestConnectionOnCheckout">false</attribute>             -->
      <!-- <attribute name="UnreturnedConnectionTimeout">0</attribute>              -->
      <!-- <attribute name="UsesTraditionalReflectiveProxies">false</attribute>     -->

      <depends>jboss:service=Naming</depends>
   </mbean>

</server>

Oracle相關

Oracle JDBC驅動提供了一個非標準的API以建立臨時BLOBCLOB,用戶必須對原始的Oracle特定鏈接實例調用方法。進階用戶可能用如上描述原始的鏈接操做來實現這個功能,但在一個單獨的jar文件(c3p0-oracle-thin-extras-0.95-pre8.jar)中,提供了一個方便的類。你能夠查詢com.mchange.v2.c3p0.dbms.OracleUtils中的API文檔獲取詳細信息。

Tomcat中部署c3p0

在Apache的Tomcat網絡應用服務中配置c3p0池數據源是很容易的。如下是一個Tomcat 5.0的案例,它是Tomcat中conf/server.xml文件中的一部分,應當被修改以適應置於<Context>元素中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<Resource name="jdbc/pooledDS" auth="Container" type="com.mchange.v2.c3p0.ComboPooledDataSource" />
<ResourceParams name="jdbc/pooledDS">
  <parameter>
    <name>factory</name>
    <value>org.apache.naming.factory.BeanFactory</value>
  </parameter>
  <parameter>
    <name>driverClass</name>
    <value>org.postgresql.Driver</value>
  </parameter>
  <parameter>
    <name>jdbcUrl</name>
    <value>jdbc:postgresql://localhost/c3p0-test</value>
  </parameter>
  <parameter>
    <name>user</name>
    <value>swaldman</value>
  </parameter>
  <parameter>
    <name>password</name>
    <value>test</value>
  </parameter>
  <parameter>
    <name>minPoolSize</name>
    <value>5</value>
  </parameter>
  <parameter>
    <name>maxPoolSize</name>
    <value>15</value>
  </parameter>
  <parameter>
    <name>acquireIncrement</name>
    <value>5</value>
  </parameter>
</ResourceParams>

對於Tomcat 5.5,使用如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
<Resource auth="Container"
	       description="DB Connection"
		  driverClass="com.mysql.jdbc.Driver"
		  maxPoolSize="4"
		  minPoolSize="2"
		  acquireIncrement="1"
		  name="jdbc/TestDB"
		  user="test"
		  password="ready2go"
		  factory="org.apache.naming.factory.BeanFactory"
		  type="com.mchange.v2.c3p0.ComboPooledDataSource"
		  jdbcUrl="jdbc:mysql://localhost:3306/test?autoReconnect=true" />

下面是一個標準的J2EE配置:你必須在你的web.xml文件中聲明你的數據源。

1
2
3
4
5
<resource-ref>
  <res-ref-name>jdbc/pooledDS</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

而後你能夠在你的網絡應用中以下配置以訪問你的數據源:

1
2
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/pooledDS");

已知缺陷

  • 鏈接和 Statement 是基於單個認證的。因此,若是一個鏈接池後端的數據源從[user=alice, password=secret1][user=bob, password=secret2]中獲取鏈接的話,就至關於有兩個不一樣的池,因此在最壞的狀況下,數據源可能要管理兩套maxPoolSize這麼多數量的鏈接。這個問題是數據源規範(它容許從多個用戶認證中獲取鏈接)形成的結果,而且同一個池中的鏈接在功能上必須是一致的。因此這個「問題」不會被改變或者修復。這裏提出來只是爲了讓你弄清楚究竟是怎麼一回事。
  • Statement池的開銷太大了。若是驅動不對PreparedStatement執行明顯的預處理,Statement池的開銷要大於它節省的時間。所以他默認是關閉的。若是你的驅動的確預處理了PreparedStatement,特別是經過 IPC 與 RDBMS 的話,你將可能會從中得到很明顯的性能提高。(經過把maxStatementsmaxStatementsPerConnection的配置屬性設置成比 0 大的數)
相關文章
相關標籤/搜索