问题是这样的,我们的一个接口服务程序在网络故障后不能自动恢复数据库连接。数据库连接的配置代码:
    private void setDataSourceBean (SyncSetting syncSetting)
    {        BeanDefinitionBuilder dataSourceBeanDefinitionBuilder = BeanDefinitionBuilder
                .rootBeanDefinition (ComboPooledDataSource.class)
                .setLazyInit (false);        dataSourceBeanDefinitionBuilder.setDestroyMethodName ("close");
        //设置jdbc name
        dataSourceBeanDefinitionBuilder.addPropertyValue ("driverClass",
                databseType.get (
                        Configuration.getConfigInstance ().getValue (
                                Constants.HIS_DATABASE_TYPE)));
        //设置数据库连接
        dataSourceBeanDefinitionBuilder.addPropertyValue ("jdbcUrl",
                syncSetting.getHisDatabaseUrlByBase64 () != null && !syncSetting.getHisDatabaseUrlByBase64 ().equals (
                        "") ? new String (
                        syncSetting.getHisDatabaseUrlByBase64 ()) : Configuration.getConfigInstance ().getValue (
                        Constants.HIS_JDBCURL));        //设置数据库用户名
        dataSourceBeanDefinitionBuilder.addPropertyValue ("user",
                syncSetting.getHisDatabaseUsername () != null && !syncSetting.getHisDatabaseUsername ().equals (
                        "") ? syncSetting.getHisDatabaseUsername () : Configuration.getConfigInstance ().getValue (
                        Constants.HIS_USER));        //设置数据库密码
        dataSourceBeanDefinitionBuilder.addPropertyValue ("password",
                syncSetting.getHisDatabasePassword () != null && !syncSetting.getHisDatabasePassword ().equals (
                        "") ? syncSetting.getHisDatabasePassword () : Configuration.getConfigInstance ().getValue (
                        Constants.HIS_PASSWORD));
        //
        dataSourceBeanDefinitionBuilder.addPropertyValue ("initialPoolSize",
                "2");
        //
        dataSourceBeanDefinitionBuilder.addPropertyValue ("maxPoolSize",
                "100");
        //
        dataSourceBeanDefinitionBuilder.addPropertyValue ("checkoutTimeout",
                "500");
        dataSourceBeanDefinitionBuilder.addPropertyValue ("maxIdleTime",
                "1800");
        dataSourceBeanDefinitionBuilder.addPropertyValue (
                "idleConnectionTestPeriod",
                "3000");
        dataSourceBeanDefinitionBuilder.addPropertyValue ("acquireIncrement",
                "2");
        dataSourceBeanDefinitionBuilder.addPropertyValue (
                "acquireRetryAttempts",
                "1000");
        hisDataSourceContext.registerBeanDefinition (
                Constants.HIS_DATASOURCE_NAME,
                dataSourceBeanDefinitionBuilder.getBeanDefinition ());
    }
这里acquireRetryAttempts设置为重试1000次。实际测试的时候如果系统启动的时候就断开数据库,系统会一直尝试重新连接,异常信息如下:com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Server connection failure during transaction. Due to underlying exception: 'java.net.ConnectException: Connection timed out: connect'.** BEGIN NESTED EXCEPTION ** java.net.ConnectException
MESSAGE: Connection timed out: connectSTACKTRACE:java.net.ConnectException: Connection timed out: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:519)
at java.net.Socket.connect(Socket.java:469)
at java.net.Socket.<init>(Socket.java:366)
at java.net.Socket.<init>(Socket.java:209)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:256)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:271)
at com.mysql.jdbc.Connection.createNewIO(Connection.java:2921)
at com.mysql.jdbc.Connection.<init>(Connection.java:1555)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:68)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:87)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1.acquireResource(C3P0PooledConnectionPool.java:83)
at com.mchange.v2.resourcepool.BasicResourcePool.assimilateResource(BasicResourcePool.java:884)
at com.mchange.v2.resourcepool.BasicResourcePool.acquireUntil(BasicResourcePool.java:601)
at com.mchange.v2.resourcepool.BasicResourcePool.access$400(BasicResourcePool.java:31)
at com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1079)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:354)
** END NESTED EXCEPTION **
Attempted reconnect 3 times. Giving up.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:888)
at com.mysql.jdbc.Connection.createNewIO(Connection.java:2997)
at com.mysql.jdbc.Connection.<init>(Connection.java:1555)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:68)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:87)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1.acquireResource(C3P0PooledConnectionPool.java:83)
at com.mchange.v2.resourcepool.BasicResourcePool.assimilateResource(BasicResourcePool.java:884)
at com.mchange.v2.resourcepool.BasicResourcePool.acquireUntil(BasicResourcePool.java:601)
at com.mchange.v2.resourcepool.BasicResourcePool.access$400(BasicResourcePool.java:31)
at com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1079)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:354)这一句Attempted reconnect 3 times. Giving up.是jdbc报的错误信息么?是指Spring数据库连接池1000次尝试重新连接,每重试一次jdbc都会尝试连接三次,三次都失败了Spring才算连接失败一次?
这段异常信息每过几秒就会出现一次,这样是我们所期望的效果。但是如果系统开始运行的时候一切正常,中间断开网络然后再连上,这时候系统就不会报错,因此也就不会试图恢复数据库连接。这样的话当需要通过接口访问数据库的时候,因为取回来的连接对象实际已经断开,执行SQL查询的时候就会报错。查询代码如下: List rows = getJdbcTemplate ().queryForList (sql.toString (),
                params, types);
我想问的是,如何才能让系统自动判断连接是否可用,并且在断开后尝试重新连接数据库?我对Java比较陌生,这个完全是别人写的代码,而且写代码的人也无法联系,希望大家解答的时候尽量详细一点。不知道我上面给出的信息是否足够,下面还需要做什么样的测试来确定问题的原因?我会在线等待并随时按要求提供更多的信息。谢谢!SpringJdbcTemplatec3p0

解决方案 »

  1.   

    MySQL wait timeout的值默认是28800 (3600*8),即一个连接在8小时内没有活动,就会自动断开该连接。 
    wait timeout的值可以设定,但最多只能是32767,不能再大了。
    在hibernate.cfg.xml中,在url的连接后加上autoReconnect=true
      

  2.   

    也有可能是mysql的驱动程序有问题,换个驱动问题就解决了。
      

  3.   

    Debug信息里面有这么一段:
    [2013-11-07 10:18:05.827-org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] DEBUG: com.ibatis.sqlmap.engine.builder.xml.DefaultSqlMapStreamMergerImpl:27 - load sql map input source successfully: com/****/***/dao/impl/Prescribe.xml这个意思是不是说这个项目用的是ibatis而不是Hibernate?怎么才能够知道持久化层的框架用得是什么呢?执行SQL的类继承结构如下:
    public class MedicalInfoCompensateDaoImpl extends BaseDAO implements MedicalInfoCompensateDao
    {
     其中BaseDAO的父类是Spring的import org.springframework.jdbc.core.support.JdbcDaoSupport;
    ...
    public class BaseDAO extends JdbcDaoSupport {这里也看不出跟ibatis或者Hibernate有什么关系啊?
      

  4.   

    加了这句
    <property name="testConnectionOnCheckout" value="true"/>
    问题解决。同时为了提高性能设置:        <property name="checkoutTimeout" value="80"/>
            <property name="maxIdleTime" value="60"/>
            <property name="idleConnectionTestPeriod" value="30"/>
            <property name="automaticTestTable" value="c3p0TestTable"/>
    谢谢上面兄弟帮忙,100分全送你了