2010-05-19 32 views
4

我有一個線程試圖連接到使用JdbcTemplate的一個數據庫,如下所示重新連接到數據庫x次:如何讓一個線程嘗試使用的JdbcTemplate

JDBCTemplate jdbcTemplate = new JdbcTemplate(dataSource); 

try{ 
    jdbcTemplate.execute(new CallableStatementCreator() { 
     @Override 
     public CallableStatement createCallableStatement(Connection con) 
     throws SQLException { 
      return con.prepareCall(query); 
     } 
    }, new CallableStatementCallback() { 
     @Override 
     public Object doInCallableStatement(CallableStatement cs) 
     throws SQLException { 
      cs.setString(1, subscriberID); 
      cs.execute(); 
      return null; 
     } 
    }); 
} catch (DataAccessException dae) { 
    throw new CougarFrameworkException(
      "Problem removing subscriber from events queue: " 
      + subscriberID, dae); 
} 

我要確保,如果上述代碼會拋出DataAccessException或SQLException,線程會等待幾秒鐘,然後嘗試重新連接,比如說5次,然後放棄。我怎樣才能做到這一點?另外,如果在執行期間數據庫關閉並再次出現,我如何確保我的程序從此恢復並繼續運行而不是拋出異常並退出?

在此先感謝。

回答

2

試試這個。我的考慮是:運行循環,直到成功執行語句。如果出現故障,則容忍失敗5次,並且每次都會等待2秒鐘以等待下一次執行。

JDBCTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
boolean successfullyExecuted = false; 
int failCount = 0; 
while (!successfullyExecuted){ 
try{ 
    jdbcTemplate.execute(new CallableStatementCreator() { 
     @Override 
     public CallableStatement createCallableStatement(Connection con) 
     throws SQLException { 
      return con.prepareCall(query); 
     } 
    }, new CallableStatementCallback() { 
     @Override 
     public Object doInCallableStatement(CallableStatement cs) 
     throws SQLException { 
      cs.setString(1, subscriberID); 
      cs.execute(); 
      return null; 
     } 
    }); 
    successfullyExecuted = true; 
} catch (DataAccessException dae) { 
    if (failedCount < 5){ 
     failedCount ++; 
     try{java.lang.Thread.sleep(2 * 1000L); // Wait for 2 seconds 
     }catch(java.lang.Exception e){} 
    }else{ 
    throw new CougarFrameworkException(
      "Problem removing subscriber from events queue: " 
      + subscriberID, dae); 
    } 
} catch (java.sql.SQLException sqle){ 
    if (failedCount < 5){ 
     failedCount ++; 
    }else{ 
    try{java.lang.Thread.sleep(2 * 1000L); // Wait for 2 seconds 
    }catch(java.lang.Exception e){} 
    throw new CougarFrameworkException(
      "Problem removing subscriber from events queue: " 
      + subscriberID, dae); 
    } 
} 
} 
+0

我會推薦使用Spring Retry模板而不是重試自定義代碼。 – 2017-09-12 20:23:04

0

是這樣的:

private int retries; 

/** 
* Make this configurable. 
*/ 
public void setRetries(final int retries) { 
    Assert.isTrue(retries > 0); 
    this.retries = retries; 

} 

public Object yourMethod() { 

    final int tries = 0; 
    Exception lastException = null; 
    for (int i = 0; i < this.retries; i++) { 
     try { 

      return jdbcTemplate.execute ... (your code here); 

     } catch (final SQLException e) { 
      lastException = e; 
     } catch (final DataAccessException e) { 
      lastException = e; 
     } 
    } 
    throw lastException; 

} 
1

您可能有必要關注Spring的Aspect支持。您所描述的是重試(常量)退避,並且您最終可能需要它到別的地方,無論是與Web服務,電子郵件服務器還是任何其他易受瞬態故障影響的複雜系統通信。例如,除非它是noRetryFor中列出的Throwable的子類,否則每當引發異常時,此簡單方法都會調用最多可達maxAttempts次數的基礎方法。

private Object doRetryWithExponentialBackoff(ProceedingJoinPoint pjp, int maxAttempts, 
     Class<? extends Throwable>[] noRetryFor) throws Throwable { 
    Throwable lastThrowable = null; 

    for (int attempts = 0; attempts < maxAttempts; attempts++) { 
     try { 
      pauseExponentially(attempts, lastThrowable); 
      return pjp.proceed(); 
     } catch (Throwable t) { 
      lastThrowable = t; 

      for (Class<? extends Throwable> noRetryThrowable : noRetryFor) { 
       if (noRetryThrowable.isAssignableFrom(t.getClass())) { 
        throw t; 
       } 
      } 
     } 
    } 

    throw lastThrowable; 
} 


private void pauseExponentially(int attempts, Throwable lastThrowable) { 
    if (attempts == 0) 
     return; 

    long delay = (long) (Math.random() * (Math.pow(4, attempts) * 100L)); 
    log.warn("Retriable error detected, will retry in " + delay + "ms, attempts thus far: " 
      + attempts, lastThrowable); 

    try { 
     Thread.sleep(delay); 
    } catch (InterruptedException e) { 
     // Nothing we need to do here 
    } 
} 

這個建議可以應用到你希望使用Spring的Aspect支持的任何bean上。有關更多詳情,請參閱http://static.springsource.org/spring/docs/2.5.x/reference/aop.html

+0

+ 1 - bye bye再見每個jdbcTemplate使用的樣板。 – mdma 2010-05-23 01:54:59

0

如何寫一個方面(DBRetryAspect)在它上面;它會更透明。

相關問題