Frage

Ich habe ein einzelner Thread zu einer Datenbank zu verbinden versucht JDBCTemplate wie folgt verwendet wird:

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

Ich möchte sicherstellen, dass, wenn der obige Code DataAccessException oder SQLException wirft, der Thread wartet ein paar Sekunden und versucht, wieder zu verbinden, sagen wir 5 weitere Male und dann aufgibt. Wie kann ich das erreichen? wenn während der Ausführung auch, geht die Datenbank nach unten und kommt wieder auf, wie kann ich sicherstellen, dass mein Programm erholt sich von diesem und läuft weiter, anstatt eine Ausnahme zu werfen und Aussteigen?

Vielen Dank im Voraus.

War es hilfreich?

Lösung

Versuchen Sie dies. Meine Überlegungen sind: eine Schleife, bis die Anweisungen erfolgreich ausgeführt laufen. Wenn ein Fehler auftritt, toleriert den Ausfall für 5 Mal und jedes Mal wird es für 2 Sekunden für die nächste Ausführung warten.

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

Andere Tipps

Es könnte sich lohnen, in die Du Spring Aspect Unterstützung zu suchen. Was Sie beschreiben, ist Neuversuch mit (konstant) Backoff, und die Chancen sind Sie schließlich es woanders brauchen werden, werden sie an einen Web-Service zu sprechen, eine E-Mail-Server oder ein anderes kompliziertes System anfällig für vorübergehende Fehler.

Zum Beispiel, diese einfache Methode ruft die zugrunde liegende Methode maxAttempts mal auf, wenn eine Ausnahme ausgelöst wird, es sei denn, es ist eine Unterklasse eines Throwable aufgeführt in noRetryFor ist.

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

könnte Dieser Rat zu jeder Bohne Sie mit Aspect Support Frühling wollen angewandt werden. Siehe http://static.springsource.org/spring/docs /2.5.x/reference/aop.html für weitere Details.

so etwas wie folgt aus:

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;

}

Wie sei es mit einer Seite (DBRetry Aspect) darüber zu schreiben;. Es wird transparenter

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top