Springboot?手動(dòng)分頁(yè)查詢分批批量插入數(shù)據(jù)的實(shí)現(xiàn)流程
前言
業(yè)務(wù)場(chǎng)景是什么?
就是數(shù)據(jù)庫(kù)的一批數(shù)據(jù),量不少,需要執(zhí)行同步插入到別的地方。
簡(jiǎn)單點(diǎn)肯定是一次性查出來(lái),然后循環(huán)一個(gè)個(gè)插入,完事。
考慮點(diǎn):
① 數(shù)據(jù)量大,一次性查出來(lái)操作,很爆炸。
② 循環(huán)里面一次一次地去插入,如果非業(yè)務(wù)場(chǎng)景必要,基本是不會(huì)在循環(huán)里面使用sql操作的。
所以該篇作為拋磚引玉(還有很多需要考慮的點(diǎn)),給出一種解決上面場(chǎng)景的代碼編寫方案, 手動(dòng)分頁(yè),查詢后批量插入。
正文
實(shí)現(xiàn)的流程簡(jiǎn)圖:

看看最終實(shí)現(xiàn)的效果,通過(guò)代碼日志記錄了這個(gè)實(shí)現(xiàn)后的效果 :

開始實(shí)戰(zhàn):
代碼大體就這樣:

代碼:
//獲取數(shù)據(jù)總計(jì)數(shù)
UserQueryCondition userQueryCondition=new UserQueryCondition();
Integer totalCount = userService.getAllUserCount(userQueryCondition);
//每批同步的數(shù)據(jù)條數(shù)
Integer batchSizeLimit = 500;
//分批切割處理
List<PageLimitDTO> pageLimitGroupList = getPageLimitGroupList(totalCount, batchSizeLimit);
int count=1;
//物理批次查詢
for (PageLimitDTO pageBatchLimit:pageLimitGroupList){
List<User> pageBatchList = userService.getPageList(
userQueryCondition, pageBatchLimit.getCurrIndex(), pageBatchLimit.getPageSize()
);
if (!CollectionUtils.isEmpty(pageBatchList)){
//批量插入
Boolean syncAddResult = userSyncService.batchSyncAdd(pageBatchList);
//做其余業(yè)務(wù)
if (syncAddResult){
log.info("第{}次,user數(shù)據(jù)批量插入成功",count);
}
}
log.info("第{}批次,user數(shù)據(jù)同步批量插入業(yè)務(wù)結(jié)束執(zhí)行",count);
count=count+1;
}切割函數(shù)getPageLimitGroupList:
public List<PageLimitDTO> getPageLimitGroupList(Integer totalCount, Integer batchSizeLimit ) {
log.info("這一次處理的總數(shù)據(jù)條數(shù)為 ={} 條, 每一批次處理?xiàng)l數(shù)為 ={} 條,現(xiàn)在開始做分批切割處理。",totalCount,batchSizeLimit);
int pageNum = totalCount / batchSizeLimit;
int surplus = totalCount % batchSizeLimit;
if (surplus > 0) {
pageNum = pageNum + 1;
}
List<PageLimitDTO> pageLimitGroupList =new LinkedList<>();
for(int i = 0; i < pageNum; i++){
Integer currIndex = i * batchSizeLimit;
PageLimitDTO pageLimitDTO=new PageLimitDTO();
pageLimitDTO.setPageSize(batchSizeLimit);
pageLimitDTO.setCurrIndex(currIndex);
pageLimitDTO.setDealDataCount(currIndex+batchSizeLimit);
pageLimitGroupList.add(pageLimitDTO);
log.info("分批切割,第={}次,每次={}條,最終會(huì)處理到={}條。",pageLimitGroupList.size(),batchSizeLimit,currIndex+batchSizeLimit);
}
log.info("這一次處理的總數(shù)據(jù)條數(shù)為 ={} 條, 每一批次處理?xiàng)l數(shù)為 ={} 條,總共切割分成了 ={} 次,一切準(zhǔn)備就緒,可以開始批量插入。",totalCount,batchSizeLimit,pageLimitGroupList.size());
return pageLimitGroupList;
}物理分頁(yè)查詢的mybatis sql寫法示例(核心手動(dòng)切割分頁(yè)查詢紅色部分):

代碼:
<select id="getPageList" resultMap="BaseResultMap">
SELECT *
FROM user
<where>
<if test="merchantId != null and merchantId != 0">
and MERCHANT_ID = #{merchantId}
</if>
<if test="nameList != null and !nameList.isEmpty()">
and NAME in
<foreach collection="nameList" separator="," open="(" close=")" item="name">
#{name}
</foreach>
</if>
</where>
LIMIT #{currIndex} , #{pageSize}
</select>批量插入示例:
<!--批量插入信息-->
<insert id="batchSyncAdd" parameterType="java.util.List">
insert into user(
id,
name,
age
)
values
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.id,jdbcType=BIGINT},
#{item.name,jdbcType=VARCHAR},
#{item.age,jdbcType=INTEGER}
)
</foreach>
</insert>然后就是我們美如畫的,手動(dòng)批次切割查詢插入:

當(dāng)前方案作為拋磚引玉,還有比較多可優(yōu)化的點(diǎn),但是我不做擴(kuò)展了,簡(jiǎn)單列舉一下:
1. 每次切割分頁(yè)查詢,其實(shí)可以優(yōu)化。 例如取上一次的id作為下一次的起始條件。
2. 同步異步的封裝,可以更動(dòng)態(tài)化。
3. 是否完全需要分批? 動(dòng)態(tài)設(shè)置數(shù)據(jù)超過(guò)多少才開始分批切割,不超過(guò),不需要走切割這些流程代碼。
到此這篇關(guān)于Springboot 手動(dòng)分頁(yè)查詢,分批批量插入數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Springboot 分頁(yè)查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Java8實(shí)現(xiàn)提高Excel讀寫效率
這篇文章主要介紹了基于Java8實(shí)現(xiàn)提高Excel讀寫效率,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Java多維數(shù)組和Arrays類方法總結(jié)詳解
這篇文章主要介紹了Java多維數(shù)組和Arrays類方法總結(jié)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
Mybatis中SqlSession下的四大對(duì)象之執(zhí)行器(executor)
mybatis中sqlsession下的四大對(duì)象是指:executor, statementHandler,parameterHandler,resultHandler對(duì)象。這篇文章主要介紹了Mybatis中SqlSession下的四大對(duì)象之執(zhí)行器(executor),需要的朋友可以參考下2019-04-04
玩轉(zhuǎn)SpringBoot中的那些連接池(小結(jié))
這篇文章主要介紹了玩轉(zhuǎn)SpringBoot中的那些連接池(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Java中轉(zhuǎn)義字符反斜杠\的代替方法及repalceAll內(nèi)涵解析
這篇文章主要介紹了Java中轉(zhuǎn)義字符反斜杠\的代替方法及repalceAll內(nèi)涵解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
詳解Java編寫并運(yùn)行spark應(yīng)用程序的方法
這篇文章主要介紹了詳解Java編寫并運(yùn)行spark應(yīng)用程序的方法,內(nèi)容詳細(xì),結(jié)合了作者實(shí)際工作中的問(wèn)題進(jìn)行具體分析,具有一定參考價(jià)值。2017-09-09
關(guān)于Java實(shí)體類Serializable序列化接口的作用和必要性解析
序列化是將對(duì)象狀態(tài)轉(zhuǎn)化為可保持或者傳輸?shù)母袷竭^(guò)程,與序列化相反的是反序列化,完成序列化和反序列化,可以存儲(chǔ)或傳輸數(shù)據(jù),一般情況下,在定義實(shí)體類時(shí)會(huì)使用Serializable,需要的朋友可以參考下2023-05-05
SpringBoot項(xiàng)目中新增脫敏功能的實(shí)例代碼
項(xiàng)目中,由于使用端有兩個(gè),對(duì)于兩個(gè)端的數(shù)據(jù)權(quán)限并不一樣。Web端可以查看所有數(shù)據(jù),小程序端只能查看脫敏后的數(shù)據(jù),這篇文章主要介紹了SpringBoot項(xiàng)目中新增脫敏功能,需要的朋友可以參考下2022-11-11
基于Java實(shí)現(xiàn)多線程下載并允許斷點(diǎn)續(xù)傳
這篇文章主要介紹了基于Java實(shí)現(xiàn)多線程下載并允許斷點(diǎn)續(xù)傳,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03

