循环处理数据的小轮子

news/2024/10/8 14:58:18/文章来源:https://www.cnblogs.com/tailife/p/18451630

1. 基于某个字段

比如要处理一批数据,把 id 作为查询条件,500 条数据作为一个批次

工具类代码如下:

public class DataLoopUtil {/*** 基于某个字段(比如 id, createTime 等), 循环处理数据* P > Param* R > Result** @param dataQueryFunction 查询数据* @param dataProcessConsumer 处理数据* @param extractParamFunction 从 R 中获取 P* @param startParam 起始参数*/public static <P, R> void processData(Function<P, List<R>> dataQueryFunction,Consumer<List<R>> dataProcessConsumer,Function<R, P> extractParamFunction,P startParam) {List<R> dataList;do {dataList = dataQueryFunction.apply(startParam);if (CollUtil.isNotEmpty(dataList)) {log.info("data process result {}", LambdaUtils.mapToList(dataList, extractParamFunction));dataProcessConsumer.accept(dataList);startParam = extractParamFunction.apply(dataList.get(dataList.size() - 1));}} while (CollUtil.isNotEmpty(dataList));log.info("processData exist start param is {}", startParam);}
}

使用代码如下

@Component
public class DataLoopService {@Resourceprivate MemberUserMapper memberUserMapper;public void loopGetMemberInfo() {DataLoopUtil.processData(getMemberQueryFn(), getMemberProcessConsumer(), MemberUserDO::getId, 600L);}// 查数据 Functionprivate Function<Long, List<MemberUserDO>> getMemberQueryFn() {return startId -> memberUserMapper.selectList(new LambdaQueryWrapper<MemberUserDO>().gt(MemberUserDO::getId, startId).last(" limit 3"));}// 处理数据 Consumerprivate Consumer<List<MemberUserDO>> getMemberProcessConsumer() {return dataList -> dataList.forEach(member -> {MemberUserDO update = new MemberUserDO();update.setId(member.getId());update.setRegisterIp(member.getId().toString());memberUserMapper.updateById(update);});}
}

2. 基于上一批字段

比如初始化部门表的 parent_ids,先从第一批开始,然后开始第二批,轮子如下

工具类代码是如下

/*** 基于上次结果,循环处理数据* 比如查询部门,先用顶级部门 id 查询,查到下级,再用下级的 ids 查下下级*/
public static <P, R> void processDataBatch(Function<Collection<P>, Collection<R>> dataQueryFunction,Consumer<Collection<R>> dataProcessConsumer,Function<Collection<R>, Collection<P>> extractParamFunction,Collection<P> startParam) {Collection<R> dataList;do {log.info("loop utils param is {}", JSONUtil.toJsonStr(startParam));dataList = dataQueryFunction.apply(startParam);if (CollUtil.isNotEmpty(dataList)) {dataProcessConsumer.accept(dataList);startParam = extractParamFunction.apply(dataList);}} while (CollUtil.isNotEmpty(dataList));log.info("processData exist start param is {}", startParam);
}

使用代码如下

@Override
public void initAncestor() {// 先查出第一批根部门List<DeptDO> deptDOList = deptMapper.selectListByParentId(Lists.newArrayList(DeptDO.PARENT_ID_ROOT));List<Long> parentIds = LambdaUtils.mapToList(deptDOList, DeptDO::getId);// 先处理根部门deptMapper.update(new LambdaUpdateWrapper<DeptDO>().set(DeptDO::getParentIds, DeptDO.PARENT_ID_ROOT_STR).eq(DeptDO::getParentId, 0L));// 循环处理DataLoopUtil.processDataBatch(getListDeptFn(),getDeptConsumer(),getParamExtractFn(),parentIds);
}////////////////////////// 下面是参数获取方法 //////////////////////////private Function<Collection<DeptDO>, Collection<Long>> getParamExtractFn() {return deptList -> LambdaUtils.mapToSet(deptList, DeptDO::getId);
}private Function<Collection<Long>, Collection<DeptDO>> getListDeptFn() {return parentIds -> deptMapper.selectListByParentId(parentIds);
}private Consumer<Collection<DeptDO>> getDeptConsumer() {return deptList -> {if (CollUtil.isEmpty(deptList)) {return;}// 批量查询父级部门Set<Long> parentIds = LambdaUtils.mapToSet(deptList, DeptDO::getParentId);List<DeptDO> parentDeptList = deptMapper.selectBatchIds(parentIds);Map<Long, DeptDO> parentMap = LambdaUtils.toMap(parentDeptList, DeptDO::getId);// 开始处理Map<Long, List<DeptDO>> deptMap = LambdaUtils.groupList(deptList, DeptDO::getParentId);deptMap.forEach((parentId, list) -> {DeptDO parent = parentMap.get(parentId);if (parent == null) {log.info("parent dept not exists, id {}", parentId);return;}list.forEach(dept -> deptMapper.update(new LambdaUpdateWrapper<DeptDO>().set(DeptDO::getParentIds, parent.getParentIds() + "," + parent.getId()).eq(DeptDO::getId, dept.getId())));});};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/809969.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux下操作Nginx相关命令

1、查看Nginx进程 ps -aux | grep nginx圈出的就是Nginx的二进制文件 2、测试Nginx配置文件 /usr/sbin/nginx -t可以看到nginx配置文件位置 3、nginx的使用(启动、重启、关闭) 首先利用配置文件启动nginx。nginx -c /usr/local/nginx/conf/nginx.conf重启服务:service nginx r…

10月8号笔记

1.StringUtil常用方法2.判断不为空:CollectionUtils.isNotEmpty():集合不为空; StringUtils.isNotBlank():String不为空; MapUtils.isNotEmpoty():Map集合判断不为空;3."::"用法:4.getRecords()用法:5.MyBatis-Plus常用方法:6.MyBatis-Plus中Page与IPage的区…

夜莺监控的机器支持挂载到多个业务组了

夜莺开源项目于国庆前夕发布了 v7.4.1 版本,修复了一些 bug,同时也带来了一些新功能。其中最重要的一个功能是:机器支持挂载到多个业务组了。本文将介绍几个重要的变更。 所有变更点feat: 左侧栏业务组新设计 feat: 机器支持了绑定到多个业务组,机器混部的场景,管理机器更…

SS241007C. 步行(walk)

待订正。SS241007C. 步行(walk) 题意 给你一个 \(n \le 3 \times 10^5\) 个结点的树,每个结点有一个权值 \(a_i\)。有 \(m \le 1.5 \times 10^6\) 次询问,每次删除一条边,然后再连上一条边。如果修改后的图不是树输出无解。否则找出一条路径,满足每个点恰好经过 \(a_i\) …

day02_基本的DOS命令

电脑常用快捷键 常用快捷键快捷键 作用CTRL + c 复制CTRL + v 粘贴CTRL + x 剪切CTRL + z 撤销CTRL + s 保存alt + f4 关闭窗口del 删除shift + del 强制删除Windows + r 打开 “运行” 窗口windows + e 打开 “我的文档”ctrl + alt + del 锁定/切换用户/注销/更改密码/任务管…

组态也能开发WEB前端 | uiotos致敬amis、nodered、appsmith、codewave、goview、dataroom、iotrouter、FUXA、乐吾乐

WEB组态开发SCADA、HMI画面、大屏可视化,还比较常见。比如下面: UIOTOS组态示例 那么常规WEB前端功能,组态能否一并做了呢?比如下面这种: UIOTOS前端示例 答案是可以的!UIOTOS支持页面无限嵌套,能实现原型即应用。现在就以一个具体小示例介绍如何实现的。 效果 如下所示…

GUI无代码小示例 - 工作流连线实现0/1连续翻转

效果 如下所示,连续点击按钮,输出0、1、0、1...。 步骤新建页面,拖入组件拖入3个组件:数学计算、输入框、按钮。如下所示: 连线和配置按钮点击 → 函数执行1减去输入,作为函数输出这样,当首次执行时,默认操作数1将减去输入的1,输出0。 函数输出→ 输入框 → 函数输入 …

Java生成条形码(亲测可通过扫码枪扫出)

Java生成条形码(亲测可通过扫码枪扫出) 秃秃爱健身该博客介绍了如何在Java项目中通过barcode4j库生成Code128条形码,解决了条形码扫不出或美观度不足的问题。提供了相关代码示例,包括Maven依赖、工具类和生成条形码的方法,可以自定义条形码的高度、宽度、是否留白和隐藏文…

点“亮”户外应用场景,来看触想高亮显示器TPC-M8的硬实力!

工业显示器作为信息可视化和人机交互的重要媒介,正在越来越多领域担当关键任务,工业显示器的可读性及耐用性,影响应用体验、设备安全和生产效率。尤其在户外,面对高低温、灰尘雨水、强光紫外线等极端因素,常规性能的工业显示器已不足以覆盖户外高风险应用需求。为此,触想…

phpvulhunter工具:静态 php 代码审计

phpvulhunter是一款PHP源码自动化审计工具,通过这个工具,可以对一些开源CMS进行自动化的代码审计,并生成漏洞报告。 1、安装 首先从github上进行获取: git clone https://github.com/OneSourceCat/phpvulhunter2、下载完成后,将工程目录放置于 WAMP 等 PHP-Web 运行环境中…

YOLOv8-seg训练与推理

1.YOLOv8-seg简介 YOLOv8-seg是YOLO系列模型的其中一个版本。YOLOv8-seg在继承YOLO系列模型高效性和准确性的基础上,增加了实例分割的能力。 2.数据集使用的数据集较简单,主要以下目录:images:存放原始图片(1500张),大小为128x128。部分如下: images_json:存放labelme标注的…

易基因: cfMeDIP-seq揭示cfDNA甲基化高效区分原发性和转移性前列腺|Nat Commun

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 前列腺癌(Prostate cancer,PCa)是男性中第二常见的恶性肿瘤,也是全球癌症相关死亡的第三大原因。虽然大多数原发性前列腺癌可以治愈,但转移性前列腺癌患者的5年生存率仍低至30%。大多数患者很快就会发展成…