كيفية جعل مؤشر ترابط يحاول إعادة الاتصال بقاعدة البيانات X مرات باستخدام JDBCTEMPHION
-
30-09-2019 - |
سؤال
لدي مؤشر ترابط واحد يحاول الاتصال بقاعدة بيانات باستخدام 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) فوقه ؛ سيكون أكثر شفافية.