4

次のように、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 回試行してから断念するようにしたいと考えています。どうすればこれを達成できますか?また、実行中にデータベースがダウンして再び起動した場合、例外をスローして終了するのではなく、プログラムがこれから回復して実行を継続できるようにするにはどうすればよいですか?

前もって感謝します。

4

4 に答える 4

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);
     }
 }
}
于 2010-05-19T15:30:45.243 に答える
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を参照してください。

于 2010-05-19T22:16:26.433 に答える
0

その上にアスペクト(DBRetryAspect)を書いてみたらどうだろう;もっと透明になる。

于 2011-01-03T06:14:38.573 に答える
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;

}
于 2010-05-19T15:30:40.737 に答える