在OSGi环境下配置hibernate的connection pool

文章讲述了在OSGi环境中遇到的MySQL连接超时问题,以及如何通过配置Hibernate和C3P0连接池来解决。在MySQL默认设置下,8小时未使用的连接会超时,这可能导致用户在次日使用系统时出现问题。作者提供了不修改MySQL配置、使用dbcp和选择c3p0连接池三种解决方案,并详细说明了如何在Hibernate中配置c3p0,以及在OSGi环境下处理单元测试失败的问题。解决方案包括设置`hibernate.c3p0.timeout`属性和调整`equinox.ds.block_timeout`的值。
摘要由CSDN通过智能技术生成

很多人都知道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>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值