解决一个数据库连接造成后台卡死的问题

      前段时间写了一个Demo项目,客户端通过网络连接,访问netty实现的一个后台获取数据。

      虽然后台netty的工作任务也是通过线程池来完成相应的任务处理,但是偶现客户端在读取数据时,读取的线程给卡住,读不到数据,并且只是偶尔出现,试过了很多次,每次在观察的时候都没有重现,甚至有压力测试都没有出现过,本地Debug也没有任务问题,通过每一步加日志,发现任务加到线程池之后最终并没有执行,线程池满掉了,开始怀凝是不是某一步出现了死锁,再仔细检查几轮代码,都没有什么点可能出死锁。

      多次出现问题之后,发现有一个规律:“往往出问题的时候,长时间没有访问后台,然后再去访问的时候比起平常访问更容易出现”

       由以上规律猜测,可能是后台的某个资源被释放或者因为过期失效,而用到的资源又只有数据库,spring配的C3P0的数据库连接池。查看配置文件:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
         destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
	<property name="jdbcUrl" value="jdbc:mysql://xx.xx.xx.xx/xxx"/>
	<property name="user" value="xxx"/>
	<property name="password" value="xxx"/>
	<property name="minPoolSize" value="1"/>
	<property name="maxPoolSize" value="20"/>
	<property name="checkoutTimeout" value="10000"/>
	<property name="maxStatementsPerConnection" value="50"/>
	<property name="testConnectionOnCheckout" value="true"/>
</bean>

配置中连接checkout是有检查的,超时也不长,按道理应该是没有问题的啊

仔细看了这参数的解释,testConnectionOnCheckout是在checkout的时候,通过对数据进行一次查询或者JDBC4以上和C3P00.9.5以后会去调用isValid() 来检查,原理都可以理解为对数据库进行一次最简单的查询。

然后也查到mysql在长时间没使用的连接,是会出现卡死的现象,也就是idle状态,联想到之前过出现C++访问Mysql也有这种问题,最后自己写了个线程,隔段时间做一次简单查询来解决,实际上我的这种情况很在checkout的时候就已经卡死,而又不是连接超时,也不是checkout超市,再看了下C3P0的参数配置,还有一个idleConnectionTestPeriod,这个就是定时去“激活”一下闲置的连接,加上之后,万事大吉,问题再也没有出现过了。另个还有一个参数官方也建议加上,配合使用,最终配置如下:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
	<property name="driverClass" value="com.mysql.jdbc.Driver"/><!-- 203.195.235.154 119.29.178.28-->
	<property name="jdbcUrl" value="jdbc:mysql://xx.xx.xx.xx/xxx"/>
	<property name="user" value="xxxxx"/>
	<property name="password" value="xxxx"/>
	<property name="minPoolSize" value="1"/>
	<property name="maxPoolSize" value="20"/>
	<property name="checkoutTimeout" value="10000"/>
	<property name="maxStatementsPerConnection" value="50"/>
	<property name="automaticTestTable" value="pooltest"/>
	<property name="testConnectionOnCheckout" value="true"/>
	<property name="testConnectionOnCheckin" value="true"/>
	<property name="idleConnectionTestPeriod" value="60"/>
</bean>

       automaticTestTable,这是可选,表示连接池做测试的时候,访问的一个表名,会自动创建,执行select 1之类的语句,表创建之后不需要手动进行修改。

记下来以备忘。

猜你喜欢

转载自qiang106.iteye.com/blog/2337183