c3p0的配置方式分爲三種,分別是
1.setters一個個地設置各個配置項
2.類路徑下提供一個c3p0.properties文件
3.類路徑下提供一個c3p0-config.xml文件html
1.setters一個個地設置各個配置項
這種方式最繁瑣,形式通常是這樣:java
01 Properties props = new Properties(); 02 InputStream in = ConnectionManager.class.getResourceAsStream("/c3p0.properties"); 03 props.load(in); 04 in.close(); 05 06 ComboPooledDataSource cpds = new ComboPooledDataSource(); 07 cpds.setDriverClass(props.getProperty("driverClass")); 08 cpds.setJdbcUrl(props.getProperty("jdbcUrl")); 09 cpds.setUser(props.getProperty("user")); 10 cpds.setPassword(props.getProperty("password"));
由於繁瑣,因此很不適合採用,因而文檔提供了另外另種方式。mysql
2. 類路徑下提供一個c3p0.properties文件
文件的命名必須是c3p0.properties,裏面配置項的格式爲:spring
1 c3p0.driverClass=com.mysql.jdbc.Driver 2 c3p0.jdbcUrl=jdbc:mysql://localhost:3306/jdbc 3 c3p0.user=root 4 c3p0.password=java
上面只提供了最基本的配置項,其餘配置項參照 文檔配置,記得是c3p0.後面加屬性名就是了,最後初始化數據源的方式就是這樣簡單: sql
1 private static ComboPooledDataSource ds = new ComboPooledDataSource(); 2 3 public static Connection getConnection() { 4 try { 5 return ds.getConnection(); 6 } catch (SQLException e) { 7 throw new RuntimeException(e); 8 } 9 }
3.類路徑下提供一個c3p0-config.xml文件
這種方式使用方式與第二種差很少,可是有更多的優勢
(1).更直觀明顯,很相似hibernate和spring的配置
(2).能夠爲多個數據源服務,提供default-config和named-config兩種配置方式
下面是一個配置模板: 數據庫
01 <c3p0-config> 02 <default-config> 03 <property name="user">root</property> 04 <property name="password">java</property> 05 <property name="driverClass">com.mysql.jdbc.Driver</property> 06 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property> 07 08 <property name="initialPoolSize">10</property> 09 <property name="maxIdleTime">30</property> 10 <property name="maxPoolSize">100</property> 11 <property name="minPoolSize">10</property> 12 </default-config> 13 14 <named-config name="myApp"> 15 <property name="user">root</property> 16 <property name="password">java</property> 17 <property name="driverClass">com.mysql.jdbc.Driver</property> 18 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property> 19 20 <property name="initialPoolSize">10</property> 21 <property name="maxIdleTime">30</property> 22 <property name="maxPoolSize">100</property> 23 <property name="minPoolSize">10</property> 24 </named-config> 25 </c3p0-config>
若是要使用default-config則初始化數據源的方式與第二種同樣,若是要使用named-config裏面配置初始化數據源,則只要使用一個帶參數的ComboPooledDataSource構造器就能夠了 緩存
private static ComboPooledDataSource ds = new ComboPooledDataSource("myApp");
下面整理一下從文檔和網上學習到的c3p0配置的理解 (user,password,driverClass,jdbcUrl沒有說的必要) 服務器
1.基本配置項網絡
01 acquireIncrement 02 default : 3 03 鏈接池在無空閒鏈接可用時一次性建立的新數據庫鏈接數 04 05 initialPoolSize 06 default : 3 07 鏈接池初始化時建立的鏈接數 08 09 maxPoolSize 10 default : 15 11 鏈接池中擁有的最大鏈接數,若是得到新鏈接時會使鏈接總數超過這個值則不會再獲取新鏈接,而是等待 12 其餘鏈接釋放,因此這個值有可能會設計地很大 13 14 maxIdleTime 15 default : 0 單位 s 16 鏈接的最大空閒時間,若是超過這個時間,某個數據庫鏈接尚未被使用,則會斷開掉這個鏈接 17 若是爲0,則永遠不會斷開鏈接 18 19 minPoolSize 20 default : 3 21 鏈接池保持的最小鏈接數,後面的maxIdleTimeExcessConnections跟這個配合使用來減輕鏈接池的負載
2.管理鏈接池的大小和鏈接的生存時間ide
01 maxConnectionAge 02 default : 0 單位 s 03 配置鏈接的生存時間,超過這個時間的鏈接將由鏈接池自動斷開丟棄掉。固然正在使用的鏈接不會立刻斷開,而是等待 04 它close再斷開。配置爲0的時候則不會對鏈接的生存時間進行限制。 05 06 maxIdleTimeExcessConnections 07 default : 0 單位 s 08 這個配置主要是爲了減輕鏈接池的負載,好比鏈接池中鏈接數由於某次數據訪問高峯致使建立了不少數據鏈接 09 可是後面的時間段須要的數據庫鏈接數不多,則此時鏈接池徹底沒有必要維護那麼多的鏈接,因此有必要將 10 斷開丟棄掉一些鏈接來減輕負載,必須小於maxIdleTime。配置不爲0,則會將鏈接池中的鏈接數量保持到minPoolSize。 11 爲0則不處理。
maxIdleTime也能夠歸屬到這一類,前面已經寫出來了。
3.配置鏈接測試:由於鏈接池中的數據庫鏈接頗有多是維持數小時的鏈接,頗有可能由於數據庫服務器的問題,網絡問題等致使實際鏈接已經無效,可是鏈接池裏面的鏈接仍是有效的,若是此時得到鏈接確定會發生異常,因此有必要經過測試鏈接來確認鏈接的有效性。
下面的前三項用來配置如何對鏈接進行測試,後三項配置對鏈接進行測試的時機。
01 automaticTestTable 02 default : null 03 用來配置測試鏈接的一種方式。配置一個表名,鏈接池根據這個表名建立一個空表, 04 而且用本身的測試sql語句在這個空表上測試數據庫鏈接 05 這個表只能由c3p0來使用,用戶不能操做,同時用戶配置的preferredTestQuery 將會被忽略。 06 07 preferredTestQuery 08 default : null 09 用來配置測試鏈接的另外一種方式。與上面的automaticTestTable兩者只能選一。 10 若是要用它測試鏈接,千萬不要設爲null,不然測試過程會很耗時,同時要保證sql語句中的表在數據庫中必定存在。 11 12 connectionTesterClassName 13 default : com.mchange.v2.c3p0.impl.DefaultConnectionTester 14 鏈接池用來支持automaticTestTable和preferredTestQuery測試的類,必須是全類名,就像默認的那樣, 15 能夠經過實現UnifiedConnectionTester接口或者繼承AbstractConnectionTester來定製本身的測試方法 16 17 idleConnectionTestPeriod 18 default : 0 19 用來配置測試空閒鏈接的間隔時間。測試方式仍是上面的兩種之一,能夠用來解決MySQL8小時斷開鏈接的問題。由於它 20 保證鏈接池會每隔必定時間對空閒鏈接進行一次測試,從而保證有效的空閒鏈接能每隔必定時間訪問一次數據庫,將於MySQL 21 8小時無會話的狀態打破。爲0則不測試。 22 23 testConnectionOnCheckin 24 default : false 25 若是爲true,則在close的時候測試鏈接的有效性。爲了提升測試性能,能夠與idleConnectionTestPeriod搭配使用, 26 配置preferredTestQuery或automaticTestTable也能夠加快測試速度。 27 28 testConnectionOnCheckout 29 default : false 30 性能消耗大。若是爲true,在每次getConnection的時候都會測試,爲了提升性能, 31 能夠與idleConnectionTestPeriod搭配使用, 32 配置preferredTestQuery或automaticTestTable也能夠加快測試速度。
4.配置PreparedStatement緩存
01 maxStatements 02 default : 0 03 鏈接池爲數據源緩存的PreparedStatement的總數。因爲PreparedStatement屬於單個Connection,因此 04 這個數量應該根據應用中平均鏈接數乘以每一個鏈接的平均PreparedStatement來計算。爲0的時候不緩存, 05 同時maxStatementsPerConnection的配置無效。 06 07 maxStatementsPerConnection 08 default : 0 09 鏈接池爲數據源單個Connection緩存的PreparedStatement數,這個配置比maxStatements更有意義,由於 10 它緩存的服務對象是單個數據鏈接,若是設置的好,確定是能夠提升性能的。爲0的時候不緩存。
5.重連相關配置
01 acquireRetryAttempts 02 default : 30 03 鏈接池在得到新鏈接失敗時重試的次數,若是小於等於0則無限重試直至鏈接得到成功 04 05 acquireRetryDelay 06 default : 1000 單位ms 07 鏈接池在得到新鏈接時的間隔時間 08 09 breakAfterAcquireFailure 10 default : false 11 若是爲true,則當鏈接獲取失敗時自動關閉數據源,除非從新啓動應用程序。因此通常不用。
我的以爲上述三個沒有更改的必要,但能夠將acquireRetryDelay配置地更短一些
6.定製管理Connection的生命週期
1 connectionCustomizerClassName 2 default : null 3 用來定製Connection的管理,好比在Connection acquire 的時候設定Connection的隔離級別,或者在 4 Connection丟棄的時候進行資源關閉,就能夠經過繼承一個AbstractConnectionCustomizer來實現相關 5 方法,配置的時候使用全類名。有點相似監聽器的做用。
例如:
01 import java.sql.Connection; 02 import com.mchange.v2.c3p0.AbstractConnectionCustomizer; 03 04 public class ConnectionCustomizer extends AbstractConnectionCustomizer{ 05 06 @Override 07 public void onAcquire(Connection c, String parentDataSourceIdentityToken) 08 throws Exception { 09 System.out.println("acquire : " + c); 10 } 11 @Override 12 public void onCheckIn(Connection c, String parentDataSourceIdentityToken) 13 throws Exception { 14 System.out.println("checkin : " + c); 15 } 16 @Override 17 public void onCheckOut(Connection c, String parentDataSourceIdentityToken) 18 throws Exception { 19 System.out.println("checkout : " + c); 20 } 21 @Override 22 public void onDestroy(Connection c, String parentDataSourceIdentityToken) 23 throws Exception { 24 System.out.println("destroy : " + c); 25 } 26 }
<property name="connectionCustomizerClassName">liuyun.zhuge.db.ConnectionCustomizer</property>
7.配置未提交的事務處理
1 autoCommitOnClose 2 default : false 3 鏈接池在回收數據庫鏈接時是否自動提交事務 4 若是爲false,則會回滾未提交的事務 5 若是爲true,則會自動提交事務 6 7 forceIgnoreUnresolvedTransactions 8 default : false 9 這個配置強烈不建議爲true。
8.配置debug和回收Connection通常來講事務固然由本身關閉了,爲何要讓鏈接池來處理這種不細心問題呢?
01 unreturnedConnectionTimeout 02 default : 0 單位 s 03 爲0的時候要求全部的Connection在應用程序中必須關閉。若是不爲0,則強制在設定的時間到達後回收 04 Connection,因此必須當心設置,保證在回收以前全部數據庫操做都可以完成。這種限制減小Connection未關閉 05 狀況的不是很適用。爲0不對connection進行回收,即便它並無關閉。 06 07 debugUnreturnedConnectionStackTraces 08 default : false 09 若是爲true而且unreturnedConnectionTimeout設爲大於0的值,當全部被getConnection出去的鏈接 10 unreturnedConnectionTimeout時間到的時候,就會打印出堆棧信息。只能在debug模式下適用,由於 11 打印堆棧信息會減慢getConnection的速度
同第七項同樣的,鏈接用完固然得close了,不要經過unreturnedConnectionTimeout讓鏈接池來回收未關閉的鏈接。
9.其餘配置項:由於有些配置項幾乎沒有本身配置的必要,使用默認值就好,因此沒有再寫出來
1 checkoutTimeout 2 default : 0 3 配置當鏈接池全部鏈接用完時應用程序getConnection的等待時間。爲0則無限等待直至有其餘鏈接釋放 4 或者建立新的鏈接,不爲0則當時間到的時候若是仍沒有得到鏈接,則會拋出SQLException
3、示例:
示例採用第二種方式:
1.c3p0.properties:
#驅動 c3p0.driverClass=com.mysql.jdbc.Driver #地址 c3p0.jdbcUrl=jdbc:mysql://localhost:3306/jdbc #用戶名 c3p0.user=root #密碼 c3p0.password=lovejava #------------------------------- #鏈接池初始化時建立的鏈接數 c3p0.initialPoolSize=3 #鏈接池保持的最小鏈接數 c3p0.minPoolSize=3 #鏈接池在無空閒鏈接可用時一次性建立的新數據庫鏈接數,default:3 c3p0.acquireIncrement=3 #鏈接池中擁有的最大鏈接數,若是得到新鏈接時會使鏈接總數超過這個值則不會再獲取新鏈接,而是等待其餘鏈接釋放,因此這個值有可能會設計地很大,default : 15 c3p0.maxPoolSize=15 #鏈接的最大空閒時間,若是超過這個時間,某個數據庫鏈接尚未被使用,則會斷開掉這個鏈接,單位秒 c3p0.maxIdleTime=100 #鏈接池在得到新鏈接失敗時重試的次數,若是小於等於0則無限重試直至鏈接得到成功 c3p0.acquireRetryAttempts=30 #鏈接池在得到新鏈接時的間隔時間 c3p0.acquireRetryDelay=1000
2.ConnectionPool
package com.study.pool; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class ConnectionPool { private DataSource ds; private static ConnectionPool pool; private ConnectionPool(){ ds = new ComboPooledDataSource(); } public static final ConnectionPool getInstance(){ if(pool==null){ try{ pool = new ConnectionPool(); }catch (Exception e) { e.printStackTrace(); } } return pool; } public synchronized final Connection getConnection() { try { return ds.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
3.PoolThread
package com.study.pool; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class PoolThread extends Thread { @Override public void run(){ ConnectionPool pool = ConnectionPool.getInstance(); Connection con = null; PreparedStatement stmt= null; ResultSet rs = null; try{ con = pool.getConnection(); stmt = con.prepareStatement("select sysdate as nowtime from dual"); rs = stmt.executeQuery(); while(rs.next()){ System.out.println(Thread.currentThread().getId()+"---------------開始"+rs.getString("nowtime")); } } catch (Exception e) { e.printStackTrace(); }finally{ try { rs.close(); stmt.close(); con.close(); } catch (SQLException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getId()+"--------結束"); } }
4.PoolMain
package com.study.pool; public class PoolMain { /** * 數據源緩衝池 實例練習 */ public static void main(String[] args) { System.out.println("緩衝池模擬開始"); PoolThread[] threads = new PoolThread[50]; for(int i=0;i<threads.length;i++){ threads[i] = new PoolThread(); } for(int i=0;i<threads.length;i++){ threads[i].start(); } } }