EasyExcel如何实现复杂数据的导入

shigen日更文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。

在我们常使用的系统中,难免会遇到数据导入的情况。其实导入做起来并不是很难,直接用到easyexcel读取数据写入到数据库即可。看似好简单的样子,是的,现在这些开源的框架已经帮我们把所有能遇到的问题都给考虑到了。那我们需要考虑到什么呢?shigen觉得最重要的是实际的业务场景。

我们在正式写代码之前,先去思考这样的几个问题:

前置思考

  • 系统的最大数据承载量是多少?我一下子解析1w+数据会不会有影响
  • 单行数据的验证怎么做
  • 数据的插入怎么插入,我一下子导入1w+数据到数据库吗
  • 我单条数据校验错了,我怎么保存给用户提示

……


这些都是要去思考的问题呀。shigen绝对没有危言耸听的意思哈,如果觉得简单点也行,那下文就不需要再看了。

记得shigen之前写过excel导入导出百万级数据的优化,这里提到了从excel导入100w数据到mysql的注意点:

从excel导入100万数据到mysql

  • 首先是easyExcel分批读取Excel中的100w数据 EasyExcelGeneralDataListener按照sheet页一行行的数据读取
  • 其次就是往DB里插入,怎么去插入这20w条数据,批量插入 同样也不能使用Mybatis的批量插入,会读取数据到内存中,事务整体提交
  • 使用JDBC+事务的批量操作将数据插入到数据库(分批读取+JDBC分批插入+手动事务控制)

当时的代码也在这里:

img

那这次的修改也是基于上次的修改,我们先来看下修改之后的效果:

我们调用接口:

接口调用结果

很好的显示了第几行什么数据的什么问题。其实我原始的数据是这样的:

原始数据

注:姓名、电话都是随机生成,并无实际参考价值。

我故意的写错了那个电话,最后我们看看数据库,数据是否是一致的。

数据库中导入的数据

代码中,我也涉及到了批量导入的策略,这个我们来看下代码运行之后的日志输出:

日志输出

发现结果还是很符合预期的,完美的实现。那接下来就是我如何实现的问题,感兴趣的伙伴可以先去我的gitee相关代码,本次的代码也参考了文章SpringBoot整合EasyExcel实现复杂Excel表格的导入&导出功能, 感谢原作者提供的案例参考。

发现代码其实写起来就是实现了easyexcelListener接口,我先展示全部的代码吧:

/*** 事件监听** @author shigenfu* @date 2023/8/20 11:14 下午*/
@RequiredArgsConstructor
public class EasyExcelGeneralDataListener extends AnalysisEventListener<UserVo> {private UserService userService;/*** 批量保存的数据行数*/private static final Integer BATCH_SIZE = 5;/*** 单次导入最大的数据量*/private static final Integer MAX_SIZE = 10000;/*** 电话验证正则*/private static final Pattern PHONE_REGEX = Pattern.compile("^1[0-9]{10}$");/*** 错误信息*/private final List<String> errorMsgList = new ArrayList<>();/*** 用于存储读取的数据*/private final List<UserVo> dataList = new ArrayList<>();public EasyExcelGeneralDataListener(UserService userService) {this.userService = userService;}@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {int totalRows = context.readRowHolder().getRowIndex() + 1;if (totalRows > MAX_SIZE) {errorMsgList.add("数据量过大,最多导入 " + MAX_SIZE + " 条数据");throw new RuntimeException("数据量过大,最多导入 " + MAX_SIZE + " 条数据");}}@Overridepublic void invoke(UserVo user, AnalysisContext context) {Integer rowIndex = context.readRowHolder().getRowIndex();// 数据验证add进入集合if (dataChecked(rowIndex, user)) {dataList.add(user);}// size是否为200000条:这里其实就是分批.当数据等于20w的时候执行一次插入if (dataList.size() >= BATCH_SIZE) {// 存入数据库:数据小于1w条使用Mybatis的批量插入即可saveData();// 清理集合便于GC回收dataList.clear();}}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {if (exception instanceof RuntimeException) {throw exception;}int rowIndex = context.readRowHolder().getRowIndex() + 1;errorMsgList.add("第" + rowIndex + "行数据异常,请检查后重新导入");}private boolean dataChecked(Integer rowIndex, UserVo user) {return usernameValid(rowIndex, user.getUsername()) && phoneValid(rowIndex, user.getPhone());}public List<String> getErrorMsgList() {return errorMsgList;}/*** 保存数据到DB*/private void saveData() {userService.importDBFromExcel10w(dataList);dataList.clear();}/*** Excel中所有数据解析完毕会调用此方法** @param context 上下文*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 保存最后的数据saveData();dataList.clear();}private boolean usernameValid(Integer rowIndex, String username) {if (StrUtil.isEmpty(username)) {errorMsgList.add("第" + rowIndex + "行'用户名'为空");return false;}return true;}private boolean phoneValid(Integer rowIndex, String phone) {// 根据正则校验if (!ReUtil.isMatch(PHONE_REGEX, phone)) {errorMsgList.add("第" + rowIndex + "行'手机号'格式错误");return false;}return true;}}

整体的一个实现关系是这样的:

实现关系图

在我们处理数据的时候,需要去实现一下对应的方法,做到数据的验证和分批次的导入。

需要注意的是:

在分批次导入的时候,我们应该尽量避免使用ORM框架,而是自己写导入的sql语句:

自己写插入的语句

另外,关于每行数据的字段校验,我们可以写的更加详细一些,或者放在另外的一个专门校验字段的类中。


以上就是今天分享的全部内容了,觉得不错的话,记得点赞 在看 关注支持一下哈,您的鼓励和支持将是shigen坚持日更的动力。同时,shigen在多个平台都有文章的同步,也可以同步的浏览和订阅:

平台账号链接
CSDNshigen01shigen的CSDN主页
知乎gen-2019shigen的知乎主页
掘金shigen01shigen的掘金主页
腾讯云开发者社区shigenshigen的腾讯云开发者社区主页
微信公众平台shigen公众号名:shigen

shigen一起,每天不一样!

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

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

相关文章

注意力机制的快速学习

注意力机制的快速学习 注意力机制 将焦点聚焦在比较重要的事物上 我&#xff08;查询对象Q&#xff09;&#xff0c;这张图&#xff08;被查询对象V&#xff09; 我看一张图&#xff0c;第一眼&#xff0c;就会判断那些东西对我而言比较重要&#xff0c;那些对于我不重要&…

Stable Diffusion XL on diffusers

Stable Diffusion XL on diffusers 翻译自&#xff1a;https://huggingface.co/docs/diffusers/using-diffusers/sdxl v0.24.0 非逐字翻译 Stable Diffusion XL (SDXL) 是一个强大的图像生成模型&#xff0c;其在上一代 Stable Diffusion 的基础上主要做了如下优化&#xff1a;…

最新版IDEA专业版大学生申请免费许可证教学(无需学校教育邮箱+官方途径+非破解手段)

文章目录 前言1. 申请学籍在线验证报告2. 进入IDEA官网进行认证3. 申请 JB (IDEA) 账号4. 打开 IDEA 专业版总结 前言 当你进入本篇文章时, 你应该是已经遇到了 IDEA 社区版无法解决的问题, 或是想进一步体验 IDEA 专业版的强大. 本文是一篇学生申请IDEA免费许可证的教学, 在学…

Android之Binder原理剖析

一&#xff1a;Binder的全面介绍 binder的出现 George Hoffman当时任Be公司的工程师&#xff0c;他启动了一个名为OpenBinder 的项目&#xff0c;在Be公司被ParmSource公司收购后&#xff0c; OpenBinder 由Dinnie Hackborn继续开发&#xff0c;后来成为管理ParmOS6 Cobalt O…

全景万店通打造掌上智慧生活助手,助力店铺全景引流

随着网络经济的崛起&#xff0c;新一代的消费群体的消费习惯逐渐变得富有个性化&#xff0c;因此他们对于传统的营销方式具有视觉疲劳&#xff0c;传统广告的效果也越发微小&#xff0c;但是请明显来代言&#xff0c;成本又十分高昂&#xff0c;那么还有什么引流好方法呢&#…

无人机高空巡查+智能视频监控技术,打造森林防火智慧方案

随着冬季的到来&#xff0c;森林防火的警钟再次敲响&#xff0c;由于森林面积广袤&#xff0c;地形复杂&#xff0c;且人员稀少&#xff0c;一旦发生火灾&#xff0c;人员无法及时发现&#xff0c;稍有疏忽就会酿成不可挽救的大祸。无人机高空巡查智能视频监控是一种非常有效的…

element-ui upload组件中将file文件数据转成二进制流数据格式

方法一 handleBeforeUpload (file)const reader new FileReader()reader.readAsArrayBuffer(file)reader.onload async function (theFile) {const binary new Blob([theFile.target.result]) // 转成二进制流数据 即binary数据格式}}方法二 const aBlob new Blob([file],…

Ultimate VFX

Ultimate VFX 构建套件:

学习笔记9——JUC三种量级的锁机制

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/197325.html 多线程访问共享资源冲突 临界区&#xff1a;一段代码块存在对共享资源的多线程读写操作&#xff0c;称这段代码块为临界区 竞态条件&#xff1a;多个线程在临界…

基于jsp+servlet的图书管理系统

基于jspservlet的图书管理系统演示地址为 图书馆后台管理系统 用户名:mr ,密码:123 图书馆管理系统主要的目的是实现图书馆的信息化管理。图书馆的主要业务就是新书的借阅和归还&#xff0c; 因此系统最核心的功能便是实现图书的借阅和归还。此外&#xff0c;还需要提供图书…

如何排查rpc mount export: RPC: Timed out问题

文章目录 问题描述查看nfs服务是否运行正常如果以上都通过,尝试下面步骤 问题描述 我们将讨论您在 NFS 客户端上看到的 NFS 错误之一的故障排除。在尝试与 NFS 相关的命令时可以看到此错误&#xff0c;如下所示&#xff1a; 通常&#xff0c;当您看到此错误时&#xff0c;您也…

两个观察伦敦银关键点位的方法

所谓关键点位&#xff0c;就是伦敦银价格测试了之后容易出现走势转向的位置。例如银价上涨至某些关键点位后出现反转下跌&#xff0c;或者跌到某些关键点位后反转上涨。我们清楚关键点位对交易的重要性之后&#xff0c;就要开始了解怎么找到这些关键点位&#xff0c;下面我们就…