使用tomcat池和Spring自动重新连接postgres

Jav*_*cia 5 postgresql spring connection-pooling

据我所知,"testOnBorrow"和"validationQuery"参数正好在我的小巷里,但它们似乎没有按预期工作.

我启动应用程序,运行一些查询,一切都很顺利.然后我重新启动postgres服务器 - 无需重启tomcat - 来测试DataSource可以处理重新连接,我得到的就是:

    This connection has been closed.; nested exception is org.postgresql.util.PSQLException: This connection has been closed.
    at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:104)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:729)

...

Caused by: org.postgresql.util.PSQLException: This connection has been closed.
    at org.postgresql.jdbc2.AbstractJdbc2Connection.checkClosed(AbstractJdbc2Connection.java:822)
    at org.postgresql.jdbc3.AbstractJdbc3Connection.prepareStatement(AbstractJdbc3Connection.java:273)
    at org.postgresql.jdbc2.AbstractJdbc2Connection.prepareStatement(AbstractJdbc2Connection.java:301)
    at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126)
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
    at org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:67)
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
    at org.apache.tomcat.jdbc.pool.interceptor.ConnectionState.invoke(ConnectionState.java:153)
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
    at org.apache.tomcat.jdbc.pool.TrapException.invoke(TrapException.java:41)
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
    at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:63)
    at $Proxy35.prepareStatement(Unknown Source)
    at org.springframework.jdbc.core.JdbcTemplate$SimplePreparedStatementCreator.createPreparedStatement(JdbcTemplate.java:1436)
Run Code Online (Sandbox Code Playgroud)

我在用:

  • 春季3.1
  • PostgreSQL 9.2.1
  • 连接池:org.apache.tomcat.jdbc.pool 7.0.25

我的Spring bean配置如下:

public DataSource dataSource() {
    org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
    // from properties file
    dataSource.setDriverClassName(environment
            .getProperty("datasource.driver"));
    dataSource.setUrl(environment.getProperty("datasource.url"));
    dataSource.setUsername(environment.getProperty("datasource.username"));
    dataSource.setPassword(environment.getProperty("datasource.password"));
    // other configurations
    dataSource.setInitialSize(10);
    dataSource.setMinIdle(10);
    dataSource.setMaxIdle(100);
    dataSource.setMaxActive(100);
    dataSource.setDefaultAutoCommit(true);
    dataSource.setMaxWait(6000);
    dataSource.setJmxEnabled(true);
    dataSource
            .setJdbcInterceptors("....ConnectionState;.....StatementFinalizer");
    dataSource.setRemoveAbandoned(true);
    dataSource.setRemoveAbandonedTimeout(10);
    dataSource.setLogAbandoned(true);
    dataSource.setTestOnBorrow(true);
    dataSource.setTestOnReturn(false);
    dataSource.setTestWhileIdle(false);
    dataSource.setUseEquals(false);
    dataSource.setFairQueue(false);
    dataSource.setTimeBetweenEvictionRunsMillis(30000);
    dataSource.setMinEvictableIdleTimeMillis(30000);
    dataSource.setValidationInterval(1800000);
    dataSource.setValidationQuery("SELECT 1");

    return dataSource;
}
Run Code Online (Sandbox Code Playgroud)

任何的想法?

谢谢

Mat*_*ood 1

仅当最初从池中借用连接时才会进行连接验证。即使在每次查询之前都进行检查,在检查和查询之间仍然会有一段时间,连接可能会丢失。所有查询都应该有某种形式的异常处理来处理查询失败——一般来说,处理错误的连接句柄,获取新的连接句柄,然后重试查询(如果可能)。

在 JDBC 标准中,有一个“connectionErrorOccurred”的回调方法,只要发生类似的情况就会调用该方法,但我对 JDBC 和 Java 的工作原理不够熟悉,不知道如何使用它(或者即使它涵盖了这个)案件)。

在任何情况下,您唯一可以知道连接是好还是坏的时候是当您尝试使用它时,并且没有连接池可以在不使用自定义调用执行并重试查询的情况下自动解决该问题,这会破坏JDBC 与标准接口的“契约”。