كيفية جعل مؤشر ترابط يحاول إعادة الاتصال بقاعدة البيانات X مرات باستخدام JDBCTEMPHION

StackOverflow https://stackoverflow.com/questions/2866594

سؤال

لدي مؤشر ترابط واحد يحاول الاتصال بقاعدة بيانات باستخدام 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 مرات ثم يستسلم. كيف يمكنني تحقيق ذلك؟ وأيضًا ، إذا سقطت قاعدة البيانات أثناء التنفيذ وتظهر مرة أخرى ، فكيف يمكنني التأكد من تعافي البرنامج من هذا واستمر في الركض بدلاً من إلقاء استثناء والخروج؟

شكرا مقدما.

هل كانت مفيدة؟

المحلول

جرب هذا. اعتباراتي هي: قم بتشغيل حلقة حتى تنفذ البيانات بنجاح. إذا كان هناك فشل ، احامل الفشل لمدة 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);
     }
 }
}

نصائح أخرى

قد يكون من المفيد لك أن تنظر في دعم جانب الربيع. ما تصفه هو إعادة المحاولة باستخدام (ثابت) ، وفرص ستحتاج إليها في النهاية في مكان آخر ، سواء كانت تتحدث إلى خدمة ويب أو خادم بريد إلكتروني أو أي نظام معقد آخر عرضة للإخفاقات العابرة.

على سبيل المثال ، تستدعي هذه الطريقة البسيطة الطريقة الأساسية لأوقات MaxAttempts كلما تم طرح استثناء ، ما لم تكن فئة فرعية من القائمة القابلة للتسمية في Nortryfor.

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

يمكن تطبيق هذه النصيحة على أي فول ترغب في استخدام دعم جانب الربيع. نرى http://static.springsource.org/spring/docs/2.5.x/reference/aop.html لمزيد من التفاصيل.

شيء من هذا القبيل:

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;

}

ماذا عن كتابة جانب (dbretryAspect) فوقه ؛ سيكون أكثر شفافية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top