c3p0資料來源的使用初步及Mysql8小時問題解決
c3p0號稱是java界最好的資料池。
c3p0的配置方式分為三種,分別是
1.setters一個個地設定各個配置項
2.類路徑下提供一個c3p0.properties檔案
3.類路徑下提供一個c3p0-config.xml檔案
我們主要說下c3p0-config.xml配置:
<c3p0-config>
//預設池配置
<default-config>
<property name="user">root</property>
<property name="password">java</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
</default-config>
//命名池配置
<named-config name="myApp">
<property name="user">root</property>
<property name="password">java</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
</named-config>
</c3p0-config>
可見c3p0可以配置在一個應用中使用多個池。換言之可以使用多個數據庫。
使用:
//使用預設池:
private static ComboPooledDataSource ds = new ComboPooledDataSource();
//使用命名池
private static ComboPooledDataSource ds = new ComboPooledDataSource("myApp");
基本配置項的介紹:
1.基本配置
acquireIncrement
default : 3
連線池在無空閒連線可用時一次性建立的新資料庫連線數
initialPoolSize
default : 3
連線池初始化時建立的連線數
maxPoolSize
default : 15
連線池中擁有的最大連線數,如果獲得新連線時會使連線總數超過這個值則不會再獲取新連線,而是等待
其他連線釋放,所以這個值有可能會設計地很大
maxIdleTime
default : 0 單位 s
連線的最大空閒時間,如果超過這個時間,某個資料庫連線還沒有被使用,則會斷開掉這個連線
如果為0,則永遠不會斷開連線
minPoolSize
default : 3
連線池保持的最小連線數,後面的maxIdleTimeExcessConnections跟這個配合使用來減輕連線池的負載
2.管理連線池的大小和連線的生存時間
maxConnectionAge
default : 0 單位 s
配置連線的生存時間,超過這個時間的連線將由連線池自動斷開丟棄掉。當然正在使用的連線不會馬上斷開,而是等待
它close再斷開。配置為0的時候則不會對連線的生存時間進行限制。
maxIdleTimeExcessConnections
default : 0 單位 s
這個配置主要是為了減輕連線池的負載,比如連線池中連線數因為某次資料訪問高峰導致建立了很多資料連線
但是後面的時間段需要的資料庫連線數很少,則此時連線池完全沒有必要維護那麼多的連線,所以有必要將
斷開丟棄掉一些連線來減輕負載,必須小於maxIdleTime。配置不為0,則會將連線池中的連線數量保持到minPoolSize。
為0則不處理。
3.配置連線測試:因為連線池中的資料庫連線很有可能是維持數小時的連線,很有可能因為資料庫伺服器的問題,網路問題等導致實際連線已經無效,但是連線池裡面的連線還是有效的,如果此時獲得連線肯定會發生異常,所以有必要通過測試連線來確認連線的有效性。
下面的前三項用來配置如何對連線進行測試,後三項配置對連線進行測試的時機。
automaticTestTable
default : null
用來配置測試連線的一種方式。配置一個表名,連線池根據這個表名建立一個空表,
並且用自己的測試sql語句在這個空表上測試資料庫連線
這個表只能由c3p0來使用,使用者不能操作,同時使用者配置的preferredTestQuery 將會被忽略。
preferredTestQuery
default : null
用來配置測試連線的另一種方式。與上面的automaticTestTable二者只能選一。
如果要用它測試連線,千萬不要設為null,否則測試過程會很耗時,同時要保證sql語句中的表在資料庫中一定存在。
connectionTesterClassName
default : com.mchange.v2.c3p0.impl.DefaultConnectionTester
連線池用來支援automaticTestTable和preferredTestQuery測試的類,必須是全類名,就像預設的那樣,
可以通過實現UnifiedConnectionTester介面或者繼承AbstractConnectionTester來定製自己的測試方法
idleConnectionTestPeriod
default : 0
用來配置測試空閒連線的間隔時間。測試方式還是上面的兩種之一,可以用來解決MySQL8小時斷開連線的問題。因為它
保證連線池會每隔一定時間對空閒連線進行一次測試,從而保證有效的空閒連線能每隔一定時間訪問一次資料庫,將於MySQL
8小時無會話的狀態打破。為0則不測試。
testConnectionOnCheckin
default : false
如果為true,則在close的時候測試連線的有效性。為了提高測試效能,可以與idleConnectionTestPeriod搭配使用,
配置preferredTestQuery或automaticTestTable也可以加快測試速度。
testConnectionOnCheckout
default : false
效能消耗大。如果為true,在每次getConnection的時候都會測試,為了提高效能,
可以與idleConnectionTestPeriod搭配使用,
配置preferredTestQuery或automaticTestTable也可以加快測試速度。
4.配置PreparedStatement快取
maxStatements
default : 0
連線池為資料來源快取的PreparedStatement的總數。由於PreparedStatement屬於單個Connection,所以
這個數量應該根據應用中平均連線數乘以每個連線的平均PreparedStatement來計算。為0的時候不快取,
同時maxStatementsPerConnection的配置無效。
maxStatementsPerConnection
default : 0
連線池為資料來源單個Connection快取的PreparedStatement數,這個配置比maxStatements更有意義,因為
它快取的服務物件是單個數據連線,如果設定的好,肯定是可以提高效能的。為0的時候不快取。
注意當資料池不再使用時需要呼叫close()方法手動關閉它配置舉例:
我的c3p0配置例項: <c3p0-config> <!--解決Mysql 8小時問題 --> <default-config> <property name="automaticTestTable">C3P0Test</property> <property name="idleConnectionTestPeriod">60</property> <!--設定為2個小時 --> <property name="maxIdleTime">60</property> <!--獲取連線時測試是否有效 ,消耗較大,不建議使用--> <!-- <property name="testConnectionCheckin">true</property> --> <!-- --> <property name="initialPoolSize">10</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">100</property> <!--獲取連線超時毫秒為單位---> <property name="checkoutTimeout">30000</property> </default-config> </c3p0-config>
解決MYSQL 8小時問題
Mysql伺服器預設的“wait_timeout”是8小時,也就是說一個connection空閒超過8個小時,Mysql將自動斷開該 connection。這就是問題的所在,在C3P0 pools中的connections如果空閒超過8小時,Mysql將其斷開,而C3P0並不知道該connection已經失效,如果這時有 Client請求connection,C3P0將該失效的Connection提供給Client,將會造成上面的異常。
解決的方法有3種:
增加wait_timeout的時間。
減少Connection pools中connection的lifetime。
測試Connection pools中connection的有效性。
C3P0增加以下配置資訊:
//自動測試的table名稱
automaticTestTable=C3P0TestTable
//set to something much less than wait_timeout, prevents connections from going stale。每個小時測試一次
idleConnectionTestPeriod = 3600
//set to something slightly less than wait_timeout, preventing 'stale' connections from being handed out最大空閒時間為2個小時
maxIdleTime = 7200
//獲取connnection時測試是否有效
testConnectionOnCheckin = true
整體說明:
<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>
補充一點,與c3p0配置無關,但是對於tomcat中配置DBCP很重要。
對於tomcat中的DBCP,也需要解決Mysql 8小時問題,所以需要這樣:
//set to 'SELECT 1'
validationQuery = "SELECT 1"
//set to 'true'
testWhileIdle = "true"
//some positive integer
timeBetweenEvictionRunsMillis = 3600000
//set to something smaller than 'wait_timeout'
minEvictableIdleTimeMillis = 18000000
//if you don't mind a hit for every getConnection(), set to "true"
testOnBorrow = "true"
參考:http://my.oschina.net/lyzg/blog/55133
http://www.blogjava.net/Alpha/archive/2009/03/29/262789.html