6

We have a webapp running in production on tomcat with a MySQL back-end. All was fine for sometime, then suddenly we started getting this exception java.sql.SQLException: Already closed.

The entire stack trace is:

DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] Fetching JDBC Connection from DataSource
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] Returning JDBC Connection to DataSource
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] Could not close JDBC Connection    
java.sql.SQLException: Already closed.
    at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:114)
    at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:191)
    at org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:333)
    at org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(DataSourceUtils.java:294)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:405)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:428)
    at com.nokia.analytics.aws.aggregate.service.importer.DBInsert.truncateTable(DBInsert.java:135)
    at com.blah.analytics.aggregate.service.importer.AggregateCollector.pullAndInsert(AggregateCollector.java:85)
    at com.blah.analytics.aggregate.service.importer.AggregateCollector.call(AggregateCollector.java:96)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:679)

We are using org.apache.commons.dbcp.BasicDataSource as our datasource. I searched quite a bit but to no avail. It doesn't occur always and hence is very hard to reproduce. It seems a problem with db connection pooling. Somewhere it was suggested to set this param as negative. Currently we are not changing of those parameters (all have default vals).

What approach should we follow to avoid it?

EDIT:

The relevant code is in (DBInsert.java)

133: String sql = "DELETE FROM "+tableName;

134: logger.debug(sql);

135: this.jdbcTemplate.execute(sql);

(133-135 are line nos. which are specified in the exception)

My datasource config:

<bean id="bisToolDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="${url}/blah_db?verifyServerCertificate=false&amp;useSSL=true&amp;requireSSL=true" />
        <property name="username" value="${uname}" />
        <property name="password" value="${passwd}" />
    </bean>
4

2 回答 2

17

造成此问题的原因是长时间未使用连接,将testOnBorrow属性添加validationQuery到您的数据源配置中,您的应用程序将正常工作。
祝你好运:)

于 2013-05-02T09:41:43.343 回答
7

正如用户NobodyElse指出的那样,问题与连接池有关。我org.apache.commons.dbcp.BasicDataSource用作数据源。应用程序的性质是,在一天中的某个固定时间会出现连接激增,而一整天根本没有连接。因此,由于池中的这个连接变得陈旧,当第二天应用程序尝试连接到数据库时,我们得到了这个异常。

基本上有两种解决方案:NobodyElse指出的一种,即使用testOnBorrow;详细信息可以在这里找到

另一个解决方案(我为我们的应用程序使用的)是完全关闭池。请注意,仅当应用程序不是数据库密集型时才这样做(在我们的例子中是这样)。所以我切换到org.springframework.jdbc.datasource.DriverManagerDataSource. 它似乎工作正常的配置是:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="${url}/blah_db?verifyServerCertificate=false&amp;useSSL=true&amp;requireSSL=true" />
        <property name="username" value="${uname}" />
        <property name="password" value="${passwd}" />
</bean>
于 2013-05-03T06:15:42.333 回答