2012-12-03 64 views
5

據我所知,「testOnBorrow」和「validationQuery」參數是我的衚衕,但他們似乎沒有按預期工作。自動重新連接postgres與tomcat池和彈簧

我啓動應用程序,運行一些查詢,一切順利。然後我重新啓動Postgres的服務器 - 無需重新啓動Tomcat的 - 要測試的數據源可以處理重新連接和我得到的是這樣的:

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) 

我使用:

  • 春3.1
  • PostgreSQL的9.2.1
  • 的連接池:org.apache.tomcat.jdbc.pool 7.0.25

我的Spring bean的conf配置如下:

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; 
} 

有什麼想法嗎?

感謝

回答

1

連接的驗證時,它最初是從池借用的只是做。即使在每個查詢之前檢查過,但在檢查和連接可能丟失的查詢之間仍然存在一段時間。所有查詢都應該有某種形式的異常處理來處理查詢失敗 - 一般來說,處理錯誤的連接句柄,獲取新的連接句柄以及重試查詢(如果可能的話)。

在JDBC標準中有一個「connectionErrorOccurred」的回調方法,當這種情況發生時應該調用它,但我對JDBC和Java如何工作以瞭解如何使用它(甚至不熟悉如果它涵蓋這種情況)。

在任何情況下,如果連接正確或不正確,您可以知道的唯一時間是當您嘗試使用它並且沒有連接池可以自動解決該問題而無需使用自定義調用執行和重試查詢,這會將JDBC「合同」分解爲標準接口。

1

我最近有同樣的問題,想要在網絡丟失時自動重新連接Tomcat JDBC連接池。和你一樣,我也發現testOnBorrow和validationInterval不爲我完成這項工作。

我終於在JdbcTemplate上創建了Around Advice(我們使用Spring的org.springframework.jdbc.core.JdbcTemplate),並在Advice中進行了重試。

Spring的配置是這樣的:

<bean id="jdbcRetryOnFailureAdvice" class="my.jdbc.adapter.JdbcRetryOnFailureAdvice"> 
    <property name="maxRetriesOnConnDrop" value="5"/> 
    <property name="retryWaitInMillis" value="5000"/> 
    <property name="sqlStatesToRetry" value="08003 08001 57P01"/> 
</bean> 

<aop:config proxy-target-class="true"> 
    <aop:aspect id="jdbcRetryOnUpdate" ref="jdbcRetryOnFailureAdvice"> 
     <aop:pointcut id="retryUpdatePointCut" 
         expression="execution(* 
         org.springframework.jdbc.core.JdbcTemplate.update(..))"/> 
     <aop:around pointcut-ref="retryUpdatePointCut" 
         method="retryOnFailure"/> 
    </aop:aspect> 
</aop:config> 

的my.jdbc.adapter.JdbcRetryOnFailureAdvice類看起來是這樣的:

public class JdbcRetryOnFailureAdvice { 

    private int maxRetriesOnConnDrop = 0; 

    private long retryWaitInMillis = 1000; 

    public Object retryOnFailure(ProceedingJoinPoint jp) throws Throwable { 
     Object result = null; 
     int retryCount = 0; 
     do { 
      try { 
       Object[] args = jp.getArgs(); 
       if (args != null && args.length > 0) 
        result = jp.proceed(jp.getArgs()); 
       else 
        result = jp.proceed(); 
       break; 
      } catch (DataAccessResourceFailureException ex) { 
       if (retryCount < maxRetriesOnConnDrop) { 
        LOG.warn("Retrying...(retryCount=" + retryCount + ")"); 
        sleep(retryWaitInMillis); 
       } else { 
        throw ex; 
       } 
      } 
      retryCount++; 
     } while (retryCount <= maxRetriesOnConnDrop); 
     return result; 
    } 
} 
0

我有類似的問題。我使用Postgres 9.4。 Spring 4和Tomcat 8.我解決了彈簧配置的問題

<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close"> 
    <property name="initialSize" value="10" /> 
    <property name="maxActive" value="25" /> 
    <property name="maxIdle" value="20" /> 
    <property name="minIdle" value="10" /> 
    <property name="driverClassName" value="org.postgresql.Driver" /> 
    <property name="url" value="${database.url}" /> 
    <property name="username" value="${database.username}" /> 
    <property name="password" value="${database.password}" /> 
    <property name="testOnBorrow" value="true" /> 
    <property name="validationQuery" value="SELECT 1" /> 
</bean> 

我測試過了。它運作良好!我關閉Postgres,所以我有這樣的日誌:

Caused by: java.net.ConnectException: Connection refused: connect 
    at java.net.DualStackPlainSocketImpl.connect0(Native Method) 

但是,當我啓動postgres,一切都很好!這兩行爲了重新連接到數據庫而做了一切:

<property name="testOnBorrow" value="true" /> 
<property name="validationQuery" value="SELECT 1" />