一、应用场景
-
在数据同步时,偶尔会出现代码异常之外的问题。例如网络异常、服务器断电…
-
如果在以上异常片段中,原始数据库新增了一批数据,同步数据库则会丢失这部分数据
二、实现思路
-
为了解决以上问题,保证原始数据库操作的每条数据都同步到同步数据库中,可以创建一个数据同步重试方法
-
由try/catch进行捕捉,在数据同步出现异常时,捕获异常再次进行数据同步
-
并且设置重试间隔时间,设置重试次数,直到异常结束完成数据同步
三、代码实现
1.使用手动阻塞当前线程方式实现
- 数据同步方法
@Slf4j
@Component
public class DataProcess implements ApplicationListener<MessageEvent> {
@Override
public void onApplicationEvent(MessageEvent event) {
CdcMessage message = event.getMessage();
// 监听到TableName表操作时,进行数据同步
if (TableName.equalsIgnoreCase(message.getTable())) {
try {
// 数据同步方法(方法内写同步逻辑)
syncInsertData(message);
} catch (Exception e) { //使用顶级异常父类,捕捉所有异常,保证数据必须同步
log.error("数据同步异常:" + e.getMessage());
// 若同步数据出现异常,进行数据重试方法
retrySyncInsertData(message);
}
}
}
}
- 数据重试方法
private void retrySyncInsertData(CdcMessage message) {
int maxRetries = 10; // 最大重试次数,10次
int retryInterval = 1000; // 重试间隔时间,单位:毫秒
int retries = 0; // 当前重试次数
for (; retries < maxRetries; retries++) {
try {
// 进行数据同步方法(方法内写同步逻辑),若成功,直接跳出循环,重试成功
syncInsertData(message);
break;
} catch (Exception e) {
// 若重试同步再次异常,则使当前线程阻塞一段时间,等待异常恢复再次重试同步
log.error("数据同步次异常,重试次数:" + (retries + 1) + "/" + maxRetries);
try {
Thread.sleep(retryInterval);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
if (retries == maxRetries) {
log.error("数据同步重试失败,超过最大次数");
}
}
2.使用spring.retry的@Retryable注解实现
- 数据同步方法添加@Retryable注解
@Slf4j
@Component
public class DataProcess implements ApplicationListener<MessageEvent> {
@Override
@Retryable(value = {Exception.class}, maxAttempts = 10, backoff = @Backoff(delay = 1000, multiplier = 2))
public void onApplicationEvent(MessageEvent event) {
CdcMessage message = event.getMessage();
// 监听到TableName表操作时,进行数据同步
if (TableName.equalsIgnoreCase(message.getTable())) {
syncInsertData(message);
}
}
}
@Retryalbe
value:捕获到的异常对象
maxAttempts:最大重试次数
delay:重试间隔(毫秒)
multiplier:一下次重试间隔较上一次的倍数(例:delay=1000,multiplier=2,1th:1s,2th:2s,3th:4s)
四、总结
总体实现步骤为:
- 数据同步时出现异常
- try捕捉到异常
- 进行数据同步重试
- 若重试成功,即可对其他数据进行同步,或完成同步
- 若重试失败,则使当前线程自我阻塞一段时间,尝试等待异常处理完成
- 再次进行数据同步重试,直到数据同步成功
或:
- 添加@Retryable注解实现