溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于Java方式如何實現(xiàn)數(shù)據(jù)同步

發(fā)布時間:2022-08-10 13:53:32 來源:億速云 閱讀:287 作者:iii 欄目:開發(fā)技術

本篇內(nèi)容介紹了“基于Java方式如何實現(xiàn)數(shù)據(jù)同步”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

業(yè)務背景

在新系統(tǒng)中設置定時任務需要實時把客戶系統(tǒng)中的數(shù)據(jù)及時同步過來,保持數(shù)據(jù)的一致性。

實現(xiàn)邏輯

1.根據(jù)客戶提供的接口,本系統(tǒng)中采用Http的Post請求方式獲取接口數(shù)據(jù)。
2.由于客戶提供的接口必帶頁碼和頁面容量,因此會涉及到多次請求接口才能拿到全量數(shù)據(jù),因此相同的操作可以采用遞歸的方式進行。
3.每次請求一次接口根據(jù)頁面容量(pageSize)可獲取多條數(shù)據(jù),此時可以采用批量添加數(shù)據(jù)庫的操作,使用批量SQL添加語句。
4.由于數(shù)據(jù)同步需要保持兩個系統(tǒng)數(shù)據(jù)的一致性,因此需要使用定時任務并規(guī)定同步頻率,例如:一天一次或者一天兩次。
5.定時任務的使用會產(chǎn)生數(shù)據(jù)重復的問題,因此根據(jù)某個唯一字段建立唯一索引來避免數(shù)據(jù)重復添加的問題。
6.唯一索引的建立可以避免同一記錄重復添加的問題,但是避免不了同一條記錄除唯一索引字段之外其它字段對應數(shù)據(jù)發(fā)生變化問題,因此使用replace into添加SQL語句可以解決此問題。

提示: a. 如果發(fā)現(xiàn)表中已經(jīng)有此行數(shù)據(jù)(根據(jù)主鍵或者唯一索引判斷)則先刪除此行數(shù)據(jù),然后插入新的數(shù)據(jù)。 b. 不然的話,直接插入新的數(shù)據(jù)。

使用技術

1.設置定時任務。
2.采用Http的Post方式獲取接口數(shù)據(jù)。
3.涉及多頁數(shù)據(jù)采用遞歸方式循環(huán)調(diào)用。
4.批量操作數(shù)據(jù)庫(replace into)。
5.建立唯一索引避免重復插入數(shù)據(jù)。

代碼詳情

1.StudentMapper.java

/**
     * 批量添加數(shù)據(jù)同步接口學生數(shù)據(jù)
     * @param studentList
     * @return
     */
    int addBatchStudent(@Param(value = "studentList") List<Student> studentList);

2.SyncStudentServiceImpl.java代碼如下:

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ***.common.utils.HttpUtils;
import ***.common.utils.StringUtils;
import ***.entity.sync.Student;
import ***.mapper.sync.StudentMapper;
import ***.service.sync.SyncStudentService;
import ***.vo.StudentVO;
import lombok.extern.slf4j.Slf4j;

/**
 * 數(shù)據(jù)同步的學生實現(xiàn)類
 * @author hc
 * @create 2021/03/25 11:20
 * @version 1.0
 * @since 1.0
 */
@Service
@Slf4j
public class SyncStudentServiceImpl implements SyncStudentService {
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private HttpUtils httpUtils;

    @Override
    public void bulkAddStudent(StudentVO studentVO) {
        log.info("調(diào)取學生接口傳的參數(shù)對象studentVO:"+studentVO);
        log.info("開始調(diào)取學生接口獲取第" + studentVO.getPageIndex() + "頁數(shù)據(jù)");
        //如何頁面容量小于100,則按100計算
        if(studentVO.getPageSize() < 100) {
            studentVO.setPageSize(100);
        }
        //根據(jù)當前頁碼和頁面容量調(diào)取獲取學生數(shù)據(jù)接口
        JSONObject jsonObject = this.sendStudentHttpPost(studentVO);
        //判斷返回JSONObject是否為null
        if (StringUtils.isNotNull(jsonObject) && jsonObject.containsKey("errcode") && jsonObject.getInteger("errcode") == 0) {
            if(jsonObject.containsKey("data")){
                JSONArray jsonArray = jsonObject.getJSONArray("data");
                //通過判斷獲取的jsonObject對象中key值為data是否為null和其 jsonArray的長度來判斷是否進行遞歸
                //提示:此判斷方法好于通過計算總頁碼的方式來遞歸拿數(shù)據(jù)(對獲取的total依賴過大,因此放棄此方式)
                if(jsonObject.getString("data") != null && jsonArray.size() > 0) {
                   log.info("當前數(shù)據(jù)加載到幾頁》》》》:{}", studentVO.getPageIndex());
                   //調(diào)取批量添加數(shù)據(jù)
                   this.addStudentCycleData(jsonObject, studentVO);
                   //頁碼加1,繼續(xù)調(diào)取下一頁數(shù)據(jù)
                      studentVO.setPageIndex(studentVO.getPageIndex() + 1);
                     //采用遞歸方式直至循環(huán)結(jié)束
                   this.bulkAddStudent(studentVO);
                }else {
                    log.info("學生數(shù)據(jù)同步結(jié)束》》》");
                }
            }
        }
    }

    /**
     * 批量添加學生數(shù)據(jù)
     * @param jsonObject
     * @param areaVO
     * @return
     */
    public void addStudentCycleData(JSONObject jsonObject, StudentVO studentVO){
        List<Student> studentList = null;
        //判斷jsonArray時候為空
        if (jsonObject != null && StringUtils.isNotBlank(jsonObject.getString("data"))) {
            //把JsonArray轉(zhuǎn)成對應實體類集合
            studentList = JSONObject.parseArray(jsonObject.getString("data"), Student.class);
        }
        try {
            log.info("學生接口第" + studentVO.getPageIndex() + "頁數(shù)據(jù)開始入庫...");
            //調(diào)取方法批量進行添加學生數(shù)據(jù)
            studentMapper.addBatchStudent(studentList);
            log.info("學生接口第" + studentVO.getPageIndex() + "頁數(shù)據(jù)入庫成功...");
        } catch (Exception e) {
            log.error("學生批量添加數(shù)據(jù)庫異常:{}", e.getMessage());
        }
    }

    /**
     * 根據(jù)studentVO(當前頁碼和頁面容量)發(fā)送獲取學生數(shù)據(jù)的請求
     * @param studentVO
     * @return
     */
    public JSONObject sendStudentHttpPost(StudentVO studentVO){
        JSONObject jsonObject = null;
        String studentUrl = "http://*****/async-api/jc/student";
        try {
            if (StringUtils.isNotEmpty(studentUrl)) {
                Map<String, Object> param = new HashMap<>();
                param.put("pageIndex", studentVO.getPageIndex());
                param.put("pageSize", studentVO.getPageSize());
                log.info("開始發(fā)起http請求...");
                jsonObject = httpUtils.sendHttpPost(param, studentUrl);
            }
        } catch (Exception e) {
            log.error("調(diào)取客戶學生同步接口出現(xiàn)異常:{},頁面容量為:{},頁碼:{}", e.getMessage(), 
            studentVO.getPageSize(), studentVO.getPageIndex());
        }
        return jsonObject;
    }
}

3.StudentVO.java代碼如下:

import lombok.Data;
/**
 * 數(shù)據(jù)同步接口獲取學生數(shù)據(jù)傳的參數(shù)VO類
 * @author hc
 * @create 2021/3/11 10:35
 * @version 1.0
 * @since 1.0
 */
@Data
public class StudentVO{
    //當前頁碼(初始值為0)
    private Integer pageIndex = 0;
    //頁碼容量
    private Integer pageSize;
}

4.HttpUtils.java代碼如下:

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import java.util.Map;

/**
 * Http請求工具類
 * @author hc
 * @create 2021/3/4
 * @version 1.0
 */
@Component
@Slf4j
public class HttpUtils {
    @Autowired
    private RestTemplate restTemplate;
    
    /**
     * 發(fā)送http的post請求方法
     * @param param
     * @return
     */
    public JSONObject sendHttpPost(Integer type, Map<String, Object> param, String url){
        log.info("調(diào)取同步接口Url:{}", url);
        JSONObject jsonObject = null;
        //發(fā)起http的post準備工作
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Type", "application/json");
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(param, httpHeaders);
        ResponseEntity<String> response = null;
        try {
            log.info("param參數(shù)為:{}",param.toString());
            response = restTemplate.postForEntity(url, httpEntity, String.class);
        } catch (HttpClientErrorException e) {
            log.error("發(fā)起http請求報錯信息:{}",e.getResponseBodyAsString());
        }
        String bodyData = response.getBody();
        if (StringUtils.isNotEmpty(bodyData)) {
            jsonObject = JSONObject.parseObject(bodyData);
        }
        return jsonObject;
    }
}

5.StudentMapper.xml的SQL語句如下:

<!-- 批量添加數(shù)據(jù)同步接口中獲取的學生數(shù)據(jù) -->
<insert id="addBatchStudent" parameterType="***.entity.sync.Student">
    replace into xf_clue_sync_student(id, student_code, student_name, status, create_date, update_date)
    <foreach collection="studentList" item="student" open="values" separator="," >
       (#{student.id,jdbcType=BIGINT}, #{student.studentCode,jdbcType=INTEGER}, #{student.studentName,jdbcType=VARCHAR}, 
        #{student.status,jdbcType=INTEGER}, #{student.createDate,jdbcType=VARCHAR}, #{student.updateDate,jdbcType=VARCHAR})
    </foreach>
</insert>

功能小結(jié)

1.定時任務配置相關代碼此處不再展示,SpringBoot框架使用注解的方式即可設置定時任務以及調(diào)取頻率。
2.數(shù)據(jù)同步接口開發(fā)需要根據(jù)具體應用場景采用不同的方法,需視情況而定,例如:也可以使用kettle工具等等。

“基于Java方式如何實現(xiàn)數(shù)據(jù)同步”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI