可参考:

https://www.cnblogs.com/ShaYeBlog/p/5762553.html

https://blog.csdn.net/li396864285/article/details/53607536

一,场景:

定时任务需要从中间表同步数据到业务表,然后更新中间表状态为已同步。

二,处理方案:

【分批处理】每次查询500条数据,对500条数据批量写入业务表,批量更新中间表状态

【循环处理】每次执行定时任务,通过do while,条件是只要能够查到中间表存在未同步的数据,就执行同步操作。这样好处:

每次跑定时任务可以尽可能的多的处理数据,甚至可以处理完一段时间内写入中间表的所有未同步数据。

可能会有疑问,如果把定时任务执行周期缩短,不也可以快速处理数据。这两种方案可以综合使用。

可能又有疑问,执行周期过短,会导致上一个任务还没处理完成,下一个任务就开始进行业务处理,引发并发问题,数据被重复获取处理。在现在这种场景,中间表数据会被重复获取,重复写入业务表,重复更新中间表。对于业务表重复写入,因为根据有唯一索引,存在更新,不存在写入,并不会导致错误;对于更新中间表,每次只是更新状态已完成,重复更新也没有问题。

其他不同场景,执行周期过短可能会引发严重问题。之前有种场景是,在仓储系统中,定时取原始数据组装成拣货单,导致原始数据被重复获取,导致重复组单,这时需要考虑业务的执行时间与定时任务的执行周期,同时考虑加分布式锁。

三,疑问:

1,每批处理500基础什么原因考虑,多条更合适,如果数据量过大引发什么问题?对于查询,可能会很慢,对于更新,可能会锁表,还是行级锁,出现锁定问题,有引发其他什么问题?

2,使用do while是否可以避免,执行周期过短导致的并发问题

因为先执行do内容,在判断条件,do中业务执行完毕只有才会进行下一次条件判断。不会存在中间表中未同步数据被重复取到的问题。

四,定时任务实现

使用的当当网的elastci-job

五,代码实现

1,定时任务类

@Component
@Slf4j
@ElasticSimpleJob(taskName = "syncBaseDeliveryAreaConfigFreshJob")
public class SyncBaseDeliveryAreaConfigFreshJob implements SimpleJob {@Resourceprivate BaseDeliveryAreaConfigFreshService baseDeliveryAreaConfigFreshService;@Overridepublic void execute(ShardingContext shardingContext) {log.info("SyncBaseDeliveryAreaConfigFreshJob start:{}", shardingContext);try {List<MidDeliveryAreaConfigFresh> list;do {list = baseDeliveryAreaConfigFreshService.selectPendingDataList(BizConstant.SPLIT_NUM);baseDeliveryAreaConfigFreshService.syncBaseDeliveryAreaConfigFresh(list);}while (CollectionUtils.isNotEmpty(list));} catch (Exception e) {log.error("SyncBaseDeliveryAreaConfigFreshJob  exception!:{}", e);}log.info("SyncBaseDeliveryAreaConfigFreshJob end");}
}

2,业务实现类

    @Transactional@Overridepublic void syncBaseDeliveryAreaConfigFresh(List<MidDeliveryAreaConfigFresh> list) {if (CollectionUtils.isEmpty(list)) {return;}// 取配送区域名称,取中间表,取结果表可能未同步List<String> deliveryAreaCodeList = list.stream().map(MidDeliveryAreaConfigFresh::getDeliveryAreaCode).distinct().collect(Collectors.toList());List<MidDeliveryAreaFresh> midDeliveryAreaFreshList = midDeliveryAreaFreshMapper.queryByDeliveryAreaCodes(deliveryAreaCodeList);Map<String, String> map = midDeliveryAreaFreshList.stream().collect(Collectors.toMap(v -> v.getDeliveryAreaCode(), v -> v.getDescription(), (a, b) -> b));// 根据结果表唯一索引分组,取中间表重复最新一条Map<String, List<MidDeliveryAreaConfigFresh>> mapGroup = list.stream().collect(Collectors.groupingBy(v ->v.getDcCode() + v.getBigCategoryCode() + v.getSmallCategoryCode() + v.getProductCode() + v.getStockLoc()));List<MidDeliveryAreaConfigFresh> resultList = mapGroup.values().stream().map(listv -> listv.get(listv.size() - 1)).collect(Collectors.toList());// 将创建时间最大的数据插入或者更新到结果表baseDeliveryAreaConfigFreshMapper.saveOrUpdateBatch(conventResult(resultList, map));// 将中间表此批次处理的所有数据状态置为已同步List<Long> ids = list.stream().map(MidDeliveryAreaConfigFresh::getId).collect(Collectors.toList());midDeliveryAreaConfigFreshMapper.updateProcessFlagByIds(ids);}@Overridepublic List<MidDeliveryAreaConfigFresh> selectPendingDataList(int num) {return midDeliveryAreaConfigFreshMapper.selectPendingDataList(num);}

3,批量更新or写入业务表

注意判断维度是什么,表的唯一索引:

void saveOrUpdateBatch(@Param("list") List<BaseDeliveryAreaConfigFresh> baseDeliveryAreaConfigFreshList);
 <insert id="saveOrUpdateBatch">insert into base_delivery_area_config_fresh (dc_code, stock_loc_code, delivery_area_code, delivery_area_name, small_category_code,big_category_code, product_code, is_delete, created_time, created_by, updated_time,updated_by)values<foreach collection="list" item="item" separator=",">(#{item.dcCode,jdbcType=VARCHAR},#{item.stockLocCode,jdbcType=VARCHAR},#{item.deliveryAreaCode,jdbcType=VARCHAR},#{item.deliveryAreaName,jdbcType=VARCHAR},#{item.smallCategoryCode,jdbcType=VARCHAR},#{item.bigCategoryCode,jdbcType=VARCHAR},#{item.productCode,jdbcType=VARCHAR},#{item.isDelete,jdbcType=INTEGER},#{item.createdTime,jdbcType=TIMESTAMP},#{item.createdBy,jdbcType=VARCHAR},#{item.updatedTime,jdbcType=TIMESTAMP},#{item.updatedBy,jdbcType=VARCHAR})</foreach>ON DUPLICATE KEY UPDATE`dc_code` = VALUES(`dc_code`),`stock_loc_code` = VALUES(`stock_loc_code`),`delivery_area_code` = VALUES(`delivery_area_code`),`delivery_area_name` = VALUES(`delivery_area_name`),`small_category_code` = VALUES(`small_category_code`),`big_category_code` = VALUES(`big_category_code`),`product_code` = VALUES(`product_code`),`is_delete` = VALUES(`is_delete`),`created_time` = VALUES(`created_time`),`updated_time` = VALUES(`updated_time`),`created_by` = VALUES(`created_by`),`updated_by` = VALUES(`updated_by`)</insert>
</mapper>

4,更新中间表

void updateProcessFlagByIds(@Param("ids") List<Long> ids);<update id="updateProcessFlagByIds">update mid_delivery_area_config_fresh set process_flag = 1where id in<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach>
</update>

关于定时任务中批量更新方案思考相关推荐

  1. php中update语句修改多个字段,Myabtis中批量更新update多字段

    在mybatis中批量更新多个字段 推荐使用如下操作: 方式1:在Dao层接口中: void updateBatch(@Param("list")List list); 在对应的m ...

  2. mybatis mysql 批量更新_mysql批量update更新,mybatis中批量更新操作

    在日常开发中,有时候会遇到批量更新操作,这时候最普通的写法就是循环遍历,然后一条一条地进行update操作.但是不管是在服务端进行遍历,还是在sql代码中进行遍历,都很耗费资源,而且性能比较差,容易造 ...

  3. Word中批量更新域的两个小方法

    一处域更新 如果只有一处需要更新,对着域右键选择 "更新域" 即可. 多处域更新 很多需要更新的时候,可以如下操作(两种方法应该都可以) 选择"打印预览",可以 ...

  4. mybatis中批量更新

    一.更新多条数据,每条数据都不一样 背景描述:通常如果需要一次更新多条数据有两个方式,(1)在业务代码中循环遍历逐条更新.(2)一次性更新所有数据(更准确的说是一条sql语句来更新所有数据,逐条更新的 ...

  5. php怎么更新多条数据,PHP中批量更新数据表中多条记录

    class test { /** * 创建像这样的查询: "IN('a','b')"; * * @author wengxianhu * @created to 2013-05-2 ...

  6. T94 EndNote Journal List批量更新方案

    问题 EndNoteJournal list有时不完整或者不规范,单个逐次修改比较费时间,而且不能复用. 导出journal list 导入到xlsx Excel中批量修改 A列原始,B列修改为规范的 ...

  7. oracle中批量更新,oracle 批量更新

    表ks_pscjjlb: 表:ks_pscjjlb_temp 现在根据ks_pscjjlb_temp表来根据ks_pscjjlb表中的cj字段的值 update ks_pscjjlb p1 set p ...

  8. mysql批量用trim限定_mybatis中批量更新sql语句,trim、foreach标签,varchar定义理解

    准备工作 现在有一张表为:student,相关字段如下: mapper层方法 int batchUpdateStudent(List studentList); xml语句 update studen ...

  9. Entity Framework Core 5中实现批量更新、删除

    本文介绍了一个在EntityFramework Core 5中不需要预先加载数据而使用一句SQL语句批量更新.删除数据的开发包,并且分析了其实现原理,并且与其他实现方案做了比较. 一.背景 随着微软全 ...

  10. Vue的批量更新原理

    简单的代码开始: var app = new Vue({el: '#app',data: {message: 'Hello Vue!'},watch: {message (val) {console. ...

最新文章

  1. CSS兼容性(IE和Firefox)技巧大全
  2. String str =new String(“abc“)和 String str = “abc“的比较
  3. Leetcode 70. 爬楼梯 动态规划 c语言
  4. Makefile写法
  5. linux将日期和日历信息追加到文件中_Linux常用指令
  6. android方法的初始化,Android小技巧:自动初始化Library
  7. 一起来学jquery!
  8. PID算法 旋转倒立摆与平衡车的区别。此贴会更新。
  9. 最新2019年dnf辅助制作视频教程
  10. c语言算个人所得税的源代码,C语言编写一个计算个人所得税的程序,要求输入收入金额,能够输...
  11. 分布式光伏系列:分布式光伏电站 运行与维护方案一览(zz)
  12. 最简单的免费安卓手机投屏电脑游戏直播工具推荐:电脑控制手机玩游戏了解一下
  13. 孙悟空这个农村人(搞笑)
  14. 展望2020:游戏本地化
  15. pycharm所有版本 http://www.jetbrains.com/pycharm/download/previous.html 打开激活窗口 选择 Activate new license
  16. python写excel标记文字颜色_[知识积累]python3使用xlwt时写入文档字体颜色和边框样式--转载...
  17. c语言Dvv实验报告,自考高等数学(工本)考试重点复习难点.pdf
  18. 如何快速恢复最近关闭的浏览器标签页面
  19. ERP-企业资源计划
  20. 【计网】第三章 数据链路层(5)广域网协议PPP、HDLC,数据链路层设备

热门文章

  1. Gradle之全局配置
  2. ReactiveCocoa之UI篇
  3. java工程展示问题
  4. python中的zookeeper-zkpython安装
  5. C#静态方法和非静态方法
  6. Java连接各种数据库
  7. SessionID的传送
  8. android 正五边形图表,Android自定义View-蜘蛛网属性图(五边形图)
  9. (转)思科VPP源码分析(feature机制分析)
  10. [RK3399][Android7.1] Pinctrl的默认配置