• Springboot 手动分页查询,分批批量插入数据


    前言

    业务场景是什么? 


    就是数据库的一批数据,量不少,需要执行同步插入到别的地方。


    简单点肯定是一次性查出来,然后循环一个个插入,完事。

    考虑点:


    ① 数据量大,一次性查出来操作,很爆炸。


    ② 循环里面一次一次地去插入,如果非业务场景必要,基本是不会在循环里面使用sql操作的。

    所以该篇作为抛砖引玉(还有很多需要考虑的点),给出一种解决上面场景的代码编写方案, 手动分页,查询后批量插入。

    正文

    实现的流程简图:

    看看最终实现的效果,通过代码日志记录了这个实现后的效果 :

     

    开始实战:

    代码大体就这样:

     代码:

    1. //获取数据总计数
    2. UserQueryCondition userQueryCondition=new UserQueryCondition();
    3. Integer totalCount = userService.getAllUserCount(userQueryCondition);
    4. //每批同步的数据条数
    5. Integer batchSizeLimit = 500;
    6. //分批切割处理
    7. List<PageLimitDTO> pageLimitGroupList = getPageLimitGroupList(totalCount, batchSizeLimit);
    8. int count=1;
    9. //物理批次查询
    10. for (PageLimitDTO pageBatchLimit:pageLimitGroupList){
    11. List<User> pageBatchList = userService.getPageList(
    12. userQueryCondition, pageBatchLimit.getCurrIndex(), pageBatchLimit.getPageSize()
    13. );
    14. if (!CollectionUtils.isEmpty(pageBatchList)){
    15. //批量插入
    16. Boolean syncAddResult = userSyncService.batchSyncAdd(pageBatchList);
    17. //做其余业务
    18. if (syncAddResult){
    19. log.info("第{}次,user数据批量插入成功",count);
    20. }
    21. }
    22. log.info("第{}批次,user数据同步批量插入业务结束执行",count);
    23. count=count+1;
    24. }

    切割函数getPageLimitGroupList:

    1. public List<PageLimitDTO> getPageLimitGroupList(Integer totalCount, Integer batchSizeLimit ) {
    2. log.info("这一次处理的总数据条数为 ={} 条, 每一批次处理条数为 ={} 条,现在开始做分批切割处理。",totalCount,batchSizeLimit);
    3. int pageNum = totalCount / batchSizeLimit;
    4. int surplus = totalCount % batchSizeLimit;
    5. if (surplus > 0) {
    6. pageNum = pageNum + 1;
    7. }
    8. List<PageLimitDTO> pageLimitGroupList =new LinkedList<>();
    9. for(int i = 0; i < pageNum; i++){
    10. Integer currIndex = i * batchSizeLimit;
    11. PageLimitDTO pageLimitDTO=new PageLimitDTO();
    12. pageLimitDTO.setPageSize(batchSizeLimit);
    13. pageLimitDTO.setCurrIndex(currIndex);
    14. pageLimitDTO.setDealDataCount(currIndex+batchSizeLimit);
    15. pageLimitGroupList.add(pageLimitDTO);
    16. log.info("分批切割,第={}次,每次={}条,最终会处理到={}条。",pageLimitGroupList.size(),batchSizeLimit,currIndex+batchSizeLimit);
    17. }
    18. log.info("这一次处理的总数据条数为 ={} 条, 每一批次处理条数为 ={} 条,总共切割分成了 ={} 次,一切准备就绪,可以开始批量插入。",totalCount,batchSizeLimit,pageLimitGroupList.size());
    19. return pageLimitGroupList;
    20. }

     

    物理分页查询的mybatis sql写法示例(核心手动切割分页查询红色部分):

     代码:

    1. <select id="getPageList" resultMap="BaseResultMap">
    2. SELECT *
    3. FROM user
    4. <where>
    5. <if test="merchantId != null and merchantId != 0">
    6. and MERCHANT_ID = #{merchantId}
    7. </if>
    8. <if test="nameList != null and !nameList.isEmpty()">
    9. and NAME in
    10. <foreach collection="nameList" separator="," open="(" close=")" item="name">
    11. #{name}
    12. </foreach>
    13. </if>
    14. </where>
    15. LIMIT #{currIndex} , #{pageSize}
    16. </select>

    批量插入示例:
     

    1. <!--批量插入信息-->
    2. <insert id="batchSyncAdd" parameterType="java.util.List">
    3. insert into user(
    4. id,
    5. name,
    6. age
    7. )
    8. values
    9. <foreach collection="list" item="item" index="index" separator=",">
    10. (
    11. #{item.id,jdbcType=BIGINT},
    12. #{item.name,jdbcType=VARCHAR},
    13. #{item.age,jdbcType=INTEGER}
    14. )
    15. </foreach>
    16. </insert>

    然后就是我们美如画的,手动批次切割查询插入:


     

    当前方案作为抛砖引玉,还有比较多可优化的点,但是我不做扩展了,简单列举一下:

    1. 每次切割分页查询,其实可以优化。 例如取上一次的id作为下一次的起始条件。
    2. 同步异步的封装,可以更动态化。
    3. 是否完全需要分批? 动态设置数据超过多少才开始分批切割,不超过,不需要走切割这些流程代码。

    等等

    好吧,该篇就到这吧。

  • 相关阅读:
    周赛368(模拟、前后缀分解、枚举+数学、预处理+划分型DP)
    基于Scala开发Spark ML的ALS推荐模型实战
    SpringBoot启动代码和自动装配源码分析
    react-redux基本使用
    两年Java开发工作经验面试总结
    基于SpringBoot的“农机电招平台”的设计与实现(源码+数据库+文档+PPT)
    【人脸生成】HiSD-通过层级风格解耦实现图到图的迁移
    flink理论干货笔记(2)
    基于阶梯碳交易的含P2G-CCS耦合和燃气掺氢的虚拟电厂优化调度(matlab代码)
    一、鼎捷T100成本系统快速上手(大楖了解)
  • 原文地址:https://blog.csdn.net/qq_35387940/article/details/125601945