2010-05-19 30 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)在它上面;它会更透明。

相关问题