一、背景
数据量较多时,我们常常遇到需要分批处理的情况,比如上千上万数据需要需要操作数据库时(入库或者更新),我们想到分批处理,或者解析文件数据量较多,我们可能多线程分批处理,每个线程执行一定的批次数据等…
不管何种场景,当我们想到分批处理时,那如何分批,怎么计算批次数呢?
tip:此处以小数据量为例:假设待处理数据总条数75,每10条数据一处理
我常用的方法总结两种供参考:
- 方法一:循环遍历待处理的处理,当到达待处理的批次或批次倍数,或最后不足一次剩余的,满足条件即执行一次分批处理操作。eg:10,20,30…7
- 方法二:根据总数计算总批次数(75/10+1=8次),每次从待处理数据集中截取要处理的数据,最后一个批次特殊处理。eg:0-9,10-19…70-74
二、代码实现:
public static void main(String[] args) {
List sourList = new ArrayList();
//1、将list中放进去75个数据--模拟待处理数据集
for (int i = 0; i < 75; i++) {
sourList.add(i);
}
//假设每N个(10个)数据一处理(实际应用中可能每N个开一个线程,或者每N个调一次数据库操作)
int batchSize = 10;
//tempList存放批次数据
List<Object> tempList = new ArrayList<Object>();
//方法一:循环遍历待处理的处理(可能多线程,可能分批次入数据库,总之需要按每次处理的大小,计算需要处理的批次数)
for (int i = 0; i < sourList.size(); i++) {
tempList.add(sourList.get(i));
//判断批次,够N个数开始处理一波
if ((i + 1) % batchSize == 0 || (i + 1) == sourList.size()) {
log.info("处理数据集:{}", tempList.toString());
//todo 你的线程处理,或者数据库操作等
tempList.clear();
}
}
log.info("************* 方法一结束 *************");
//方法二:根据总数计算总批次数,每次从待处理数据集中截取要处理的数据
int count = sourList.size();
int totalPages = (count % batchSize > 0) ? (count / batchSize + 1) : (count / batchSize);
log.info("待处理数据总条数:{},总批次数:{}", count, totalPages);
int startIndex = 0;
int endIndex = 0;
if (totalPages > 0) {
//循环批次数,计算待处理数据下标
for (int pageNum = 1; pageNum <= totalPages; pageNum++) {
//每批次计算要处理的数据起始位置。终止位置
List subList = new ArrayList();
startIndex = ((pageNum - 1) * batchSize);
if (pageNum == totalPages) {
//考虑最后一个批次特殊处理
subList = sourList.subList(startIndex, count);
} else {
endIndex = startIndex + batchSize;
subList = sourList.subList(startIndex, endIndex);
}
//todo 你的线程处理,或者数据库操作等
log.info("处理第{}批次:{}", pageNum, subList.toString());
}
}
log.info("************* 方法二结束 *************");
}
========================打印结果:
17:42:03.357 处理数据集:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
17:42:03.368 处理数据集:[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
17:42:03.368 处理数据集:[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
17:42:03.368 处理数据集:[30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
17:42:03.368 处理数据集:[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
17:42:03.368 处理数据集:[50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
17:42:03.368 处理数据集:[60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
17:42:03.368 处理数据集:[70, 71, 72, 73, 74]
17:42:03.368 ************* 方法一结束 *************
17:42:03.368 待处理数据总条数:75,总批次数:8
17:42:03.369 处理第1批次:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
17:42:03.369 处理第2批次:[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
17:42:03.369 处理第3批次:[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
17:42:03.369 处理第4批次:[30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
17:42:03.369 处理第5批次:[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
17:42:03.369 处理第6批次:[50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
17:42:03.369 处理第7批次:[60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
17:42:03.369 处理第8批次:[70, 71, 72, 73, 74]
17:42:03.369 ************* 方法二结束 *************
这样每一波分批待处理的数据集合,以及位置你都能get到了,也就可以进行你的业务逻辑操作了,入库或者开线程了。
三、分页查询下游批次处理场景
如果是分页查询下游或者其他接口循环处理场景:
//每次导出或者查询下游接口等分页页大小(10页一查)
public final static int PERSIZE = 10;
//查询第一次数据(返回的分页信息page中包含总页数、总条数)
Page<OrderInfoDTO> firstBOList = orderRepository.queryPrescriptionByOrderId(param);
//处理第一页查询回来的数据
if (CollectionUtil.isNotEmpty(firstBOList)) {
log.info("处理数据{}条 ", firstBOList.size());
}
//页数大于1继续查询
int totalPages=firstBOList.getTotalPage();
if (totalPages > 1) {
for (int pageNum = 2; pageNum <= totalPages; pageNum++) {
query.setPageSize(PERSIZE);
query.setPageNo(pageNum);
Page<OrderInfoDTO> list = orderRepository.queryPrescriptionByOrderId(param);
//todo 处理结果集
log.info("处理第{}批次数据{}条 ", pageNum, list.size());
}
}
版权声明:本文为weixin_47061482原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。