在OSGi環境下配置hibernate的connection pool

很多人都知道MySQL的默認設置中含有一個connection timeout屬性,當一個connection在8小時之內沒有使用的話,就會timeout。在web系統開發中,比如一個用戶今天下午下班前使用了,第二天早上來上班時顯然已經超過了8小時,他就會發現系統出現了問題,所以需要從數據庫pull data的request都得不到response。


筆者前陣子開發的一個項目就遇到了這樣一個問題,之前QA測試的時候主要使用了SQL Server,現在產品deliver之後有一個客戶使用mysql,就發現了這個問題。筆者的這個項目因爲要支持多種關係型數據庫,所以使用了hibernate作爲ORM層實現。


解決這個問題顯然有這麼幾種方法:

1、修改MySQL的配置,將8小時改成更大的數值,比如1周。這是最cheap的辦法,需要麻煩不一定懂計算機知識的用戶配置本地mysql的參數,這是無法接受的。

2、採用dbcp來配置連接池(connection pool),但這樣就限制了application server的選擇,只能選用apache的server了。(如何配置dbcp

3、採用c3p0 connection pool,這是當前市面上robust的工具,非常值得信賴。


OK,下一步就是如何在hibernate中配置c3p0。先下載一個hibernate-c3p0.jar,如果使用maven的話,把下面的dependency加到pom.xml裏面

<!-- Hibernate c3p0 connection pool -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-c3p0</artifactId>
			<version>3.6.3.Final</version>
		</dependency>

google一下可以發現很多標準配置的實例,這邊隨便選取一份在hibernate.cfg.xml中的實例

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
  <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
  <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:MKYONG</property>
  <property name="hibernate.connection.username">mkyong</property>
  <property name="hibernate.connection.password">password</property>
  <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
  <property name="hibernate.default_schema">MKYONG</property>
  <property name="show_sql">true</property>
 
  <property name="hibernate.c3p0.min_size">5</property>
  <property name="hibernate.c3p0.max_size">20</property>
  <property name="hibernate.c3p0.timeout">300</property>
  <property name="hibernate.c3p0.max_statements">50</property>
  <property name="hibernate.c3p0.idle_test_period">3000</property>
 
  <mapping class="com.mkyong.user.DBUser"></mapping>
</session-factory>
</hibernate-configuration>

筆者項目中的hibernate datastore factory是動態實現,所以採用的是programmatic way如下(本質上和使用hibernate.cfg.xml配置文件一樣)。

properties.setProperty(Environment.CONNECTION_PROVIDER, "org.hibernate.connection.C3P0ConnectionProvider");
properties.setProperty(Environment.C3P0_ACQUIRE_INCREMENT, "1");
properties.setProperty(Environment.C3P0_MIN_SIZE, "10");
properties.setProperty(Environment.C3P0_MAX_SIZE, "100");
properties.setProperty(Environment.C3P0_TIMEOUT, "300");
properties.setProperty(Environment.C3P0_MAX_STATEMENTS, "0");
properties.setProperty(Environment.C3P0_IDLE_TEST_PERIOD, "3000");

其中connection provider這條屬性對於hibernate 3.x 版本是必須的!

這些屬性中重點說一條:hibernate.c3p0.timeout。它用來規定一個閒置的connection過了多久之後會從connection pool中被清除掉。只要將這個值設置成小於8小時,則當一個connection閒置不到mysql timeout時間的時候就會被清除掉,也就不會被當成有效connection來調用,問題也就解決了。

到這裏通常問題可以解決了,但筆者的項目更多一個難點,是基於OSGi的。OSGi是一種模塊化的開發方式,每個功能都是一個模塊(bundle),模塊可以提供服務,同時也可以註冊使用其他模塊的服務,比如hibernate就是一個bundle,它註冊ORM的服務,諸如此類。很顯然,c3p0連接池也將以提供服務的bundle的形式出現,於是在Eclipse裏面專門創建一個plugin project,把hibernate-c3p0.jar拷貝進去,設置build path,設置MANIFEST,export jar裏面的package。然後在提供data binding(hibernate)的bundle中使用c3p0提供的服務:把c3p0這個bundle加爲依賴,然後將上面的

properties.setProperty(...)

設置好。發現這樣maven是可以build整個項目的,但是unit test怎麼也通不過,錯誤如下

!ENTRY org.eclipse.equinox.ds 2 0 2012-06-18 14:41:47.152
!MESSAGE [SCR - WorkThread] Timeout occurred! Thread was blocked on processing [QueuedJob] WorkPerformer: org.eclipse.equinox.internal.ds.SCRManager@765e06ef; actionType 1

!ENTRY org.eclipse.equinox.ds 2 0 2012-06-18 14:41:47.175
!MESSAGE [SCR] Enabling components of bundle com.company.product.configuration did not complete in 30000 ms
這是什麼原因呢?原來Equinox(OSGi的平臺)也有一個系統設置,叫做“equinox.ds.block_timeout”,默認值爲30000毫秒,即30秒。任何一個user component的activate或者bind方法都不能超過這個時間,如果在規定時間(30秒)內不能完成,則一個新的dispatcher線程就會負責完成剩餘的任務。(Equinox的runtime option

最直接的解決方法是把這個值調大,筆者先在Eclipse run config的參數設置中把這個屬性設爲1分鐘

-Dequinox.ds.block_timeout=60000

問題就解決了,在Eclipse中跑單元測試通過。


然後還需要把這個屬性設置放到maven中(否則maven build中的unit test也還是會fail)

將-Dequinox.ds.block_timeout=60000設爲argLine即可

<build>
		<plugins>
			<plugin>
				<groupId>org.eclipse.tycho</groupId>
				<artifactId>tycho-surefire-plugin</artifactId>
				<version>0.12.0</version>
				<configuration>
					<argLine>-Dequinox.ds.block_timeout=60000</argLine>
				</configuration>
			</plugin>
		</plugins>
</build>




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章