基于Java方式實現(xiàn)數(shù)據(jù)同步
本文實例為大家分享了Java方式實現(xiàn)數(shù)據(jù)同步的具體代碼,供大家參考,具體內容如下
使用java方式實現(xiàn)兩個系統(tǒng)之間數(shù)據(jù)的同步。
業(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.定時任務的使用會產生數(shù)據(jù)重復的問題,因此根據(jù)某個唯一字段建立唯一索引來避免數(shù)據(jù)重復添加的問題。
6.唯一索引的建立可以避免同一記錄重復添加的問題,但是避免不了同一條記錄除唯一索引字段之外其它字段對應數(shù)據(jù)發(fā)生變化問題,因此使用replace into添加SQL語句可以解決此問題。
提示: a. 如果發(fā)現(xiàn)表中已經有此行數(shù)據(jù)(根據(jù)主鍵或者唯一索引判斷)則先刪除此行數(shù)據(jù),然后插入新的數(shù)據(jù)。 b. 不然的話,直接插入新的數(shù)據(jù)。
使用技術
1.設置定時任務。
2.采用Http的Post方式獲取接口數(shù)據(jù)。
3.涉及多頁數(shù)據(jù)采用遞歸方式循環(huán)調用。
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("調取學生接口傳的參數(shù)對象studentVO:"+studentVO); ? ? ?? ?log.info("開始調取學生接口獲取第" + studentVO.getPageIndex() + "頁數(shù)據(jù)"); ? ? ?? ?//如何頁面容量小于100,則按100計算 ? ? ?? ?if(studentVO.getPageSize() < 100) { ? ? ?? ??? ?studentVO.setPageSize(100); ? ? ?? ?} ? ? ? ? //根據(jù)當前頁碼和頁面容量調取獲取學生數(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()); ? ? ?? ? ? ? ? ? ? //調取批量添加數(shù)據(jù) ? ? ? ? ? ? ? ? ? ?this.addStudentCycleData(jsonObject, studentVO); ? ? ? ? ? ? ? ? ? ?//頁碼加1,繼續(xù)調取下一頁數(shù)據(jù) ? ? ? ? ? ? ? ??? ? ? studentVO.setPageIndex(studentVO.getPageIndex() + 1); ? ? ? ? ? ? ? ?? ? ? //采用遞歸方式直至循環(huán)結束 ? ? ? ? ? ? ? ? ? ?this.bulkAddStudent(studentVO); ? ? ? ? ? ? ?? ?}else { ?? ??? ??? ??? ??? ?log.info("學生數(shù)據(jù)同步結束》》》"); ?? ??? ??? ??? ?} ? ? ? ? ? ? } ?? ??? ?} ? ? } ? ? /** ? ? ?* 批量添加學生數(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轉成對應實體類集合 ? ? ? ? ?? ?studentList = JSONObject.parseArray(jsonObject.getString("data"), Student.class); ? ? ? ? } ? ? ? ? try { ? ? ? ? ?? ?log.info("學生接口第" + studentVO.getPageIndex() + "頁數(shù)據(jù)開始入庫..."); ? ? ? ? ?? ?//調取方法批量進行添加學生數(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("調取客戶學生同步接口出現(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("調取同步接口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>
功能小結
1.定時任務配置相關代碼此處不再展示,SpringBoot框架使用注解的方式即可設置定時任務以及調取頻率。
2.數(shù)據(jù)同步接口開發(fā)需要根據(jù)具體應用場景采用不同的方法,需視情況而定,例如:也可以使用kettle工具等等。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
SpringBoot實現(xiàn)JPA多數(shù)據(jù)源配置小結
本文主要介紹了SpringBoot實現(xiàn)JPA多數(shù)據(jù)源配置小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-01-01Java使用組合模式實現(xiàn)表示公司組織結構功能示例
這篇文章主要介紹了Java使用組合模式實現(xiàn)表示公司組織結構功能,簡單描述了組合模式的概念、功能并結合實例形式分析了Java使用組合模式實現(xiàn)公司組織結構表示功能具體操作步驟與相關注意事項,需要的朋友可以參考下2018-05-05MyBatis動態(tài)SQL實現(xiàn)配置過程解析
這篇文章主要介紹了MyBatis動態(tài)SQL實現(xiàn)配置過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03