【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据

简介: 【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据


       在公司开发时,遇到一个很常见的导入功能的需求,需要导入Excel文件,由此想到了阿里巴巴的EasyExcel这个方便的工具,当客户给我说需要支持大数据量导入时,我想到了使用线程池来多线程处理导入数据库这个操作。由此本章记录一下这次操作。

       首先,整体的大概流程差不多是这个样子:

效果:


       真实项目上是公司封装的RPC框架,这次demo直接使用的前面的整合mybatis-plus的demo来写的。

       首先看下目录结构:

       图片中框选部分就是本章需要修改到的或者新创建的文件,后面一一解读,下面的描述可以对标这个图片中的类名。

       然后介绍下本章需要做的准备工作:

  • 数据库表
  • 修改application配置文件,修改tomcat的最大文件上传限制(否则excel文件太大,上传会报错)
  • 开启mybatis-plus的批量插入功能,mybatis-plus默认只有insert这个单条插入功能(若自己的项目不使用这个,则不需要,这只是我的demo上没有批量插入方法)
  • 创建excel多线程导入接口所需的各个类


一、准备数据库和Excel文件

CREATE TABLE `deadman` (
  `uid` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '主键',
  `idCard` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '身份证号',
  `userName` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '死者姓名',
  `sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '死者性别',
  `age` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '死者年龄',
  `reason` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '死因',
  `house` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '安排地狱层数',
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin;


二、引入所需依赖

       主要是导入easyExcel所涉及的依赖,如下:


三、修改配置文件,修改文件大小默认限制

       这个必须修改,不然后面接口都进不去,默认tomcat服务器是限制了上传文件的大小的。

spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB
server:
  tomcat:
    max-swallow-size: 100MB

四、开启mybatis-plus的批量保存功能

       这次demo整合的rpc框架是Mybatis-plus,所以找了一个方法去实现批量保存,如下:

1、新建一个SpiceSqlInjector类

PS:注意框选部分类名。

2、创建SpiceBaseMapper接口类

PS:本来是业务的接口层去继承BaseMapper,此处又它去继承BaseMapper,然后加如上图这个方法,注意名称必须是这个否则后面调用该方法会报错。

3、创建业务所需的Mapper层

继承刚才自定义的接口类。

由此就可以通过注入DeadManMapper调用上面的方法实现批量插入了。

如下:


五、创建所需工具类

       在通过EasyExcel导入时,会涉及到一些数据类型不满足入参之类的,本次demo涉及到如下工具类。

1、MultipartFileToFileUtils

       将传入的MultipartFile类型转为File类型,Controller接收到的是MultipartFile类型,EasyExcel.read方法所需要的是File类型。

2、SpringJobBeanFactory

       在监听器类注入mappe时会报空指针,使用如下工具类继承ApplicationContextAware,获取bean对象。


六、创建业务各层代码

1、controller层

2、映射数据库的实体类

       关于mybatis-plus相关的注解可以去看看前面的文章。

3、easyExcel的实体类

       index指的是excel表上面的行编号,例如

4、service层

5、service的实现类层

       上面的方法是多线程处理的事件监听器,下面的是单线程的事件监听器,后面针对两种方式都做一下对比。


七、创建easyExcel事件监听器

1、单线程的事件监听器

       解析:该监听器继承自AnalysisEventListener类,泛型指定为上面easyExcel指定的实体类对象类。重写该类的两个方法:invoke和doAfterAllAnalysed。

invoke():该方法会从excel表的第二行开始读取数据。

doAfterAllAnalysed():当invoke将excel的数据全部解析完后,会执行该方法,所以在该类进行数据的入库即可。

       此时,单线程的导入已经完成,我们最后再对比测试两种监听器的效率,现在创建多线程事件监听器。

2、多线程的事件监听器

       解析:同样是重写上面说的那两个方法。invoke方法的处理不变,修改doAfterAllAnalysed方法的处理,在该方法通过创建线程池的方法,将创建的线程任务提交到线程池,让线程池进行多线程任务的执行,从而实现多线程执行导入操作。

流程:创建线程池——》计算每个线程需要处理的数据——》创建CountDownLatch对象(保证最后每个线程会回到主线程)——》循环线程数量并提交线程任务到线程池——》执行CountDownLatch对象的await方法,让当前线程处于等待状态,等待CountDownLatch减少为1后会唤醒当前线程——》每个线程处理自己的数据并在处理完后执行CountDownLatch对象的countDown方法,让CountDownLatch对象的值减一——》当CountDownLatch的值为0时(说明线程池类的线程任务以及执行完成),执行主线程的代码——》关闭线程池


八、创建自定义线程类

       此步骤创建上面描述的线程任务类。

       实现Callable或者Runable或者继承Thread都行,此处实现Runable,重写run方法。

       根据传入的划分给他的数据区间,将该区间的数据通过subList方法取出来之后,执行上面实现的批量插入方法进行数据的入库操作。为了防止代码出现问题不执行coutDown方法,将该句代码写入finally。

PS:CountDownLatch的两个方法(countDown,await)配合使用,保证每个线程的代码执行时,主线程进入等待,然后等各个线程任务执行完后,又回到主线程进行执行。


九、测试单线程和多线程处理的效率

       上面已经完成了单线程和多线程事件监听器的编写,下面开始测试两者的效率。

1、使用单线程事件监听器

 

       结果:100033条数据,数据正确。

2、使用多线程事件监听器

       结果:100033条数据,数据正确,确实快了很多。


       我觉得对于业务简单的多线程处理类似场景的都可以拿这个demo拿去改造一下,如果有问题,谢谢大家指出。瑞思拜。

目录
相关文章
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
1279 0
|
Java 索引
多线程向设备发送数据
多线程向设备发送数据
247 0
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
499 62
|
缓存 安全 Java
使用 Java 内存模型解决多线程中的数据竞争问题
【10月更文挑战第11天】在 Java 多线程编程中,数据竞争是一个常见问题。通过使用 `synchronized` 关键字、`volatile` 关键字、原子类、显式锁、避免共享可变数据、合理设计数据结构、遵循线程安全原则和使用线程池等方法,可以有效解决数据竞争问题,确保程序的正确性和稳定性。
532 57
|
SQL 数据建模 BI
【YashanDB 知识库】用 yasldr 配置 Bulkload 模式作单线程迁移 300G 的业务数据到分布式数据库,迁移任务频繁出错
问题描述 详细版本:YashanDB Server Enterprise Edition Release 23.2.4.100 x86_64 6db1237 影响范围: 离线数据迁移场景,影响业务数据入库。 外场将部分 NewCIS 的报表业务放到分布式数据库,验证 SQL 性能水平。 操作系统环境配置: 125G 内存 32C CPU 2T 的 HDD 磁盘 问题出现的步骤/操作: 1、部署崖山分布式数据库 1mm 1cn 3dn 单线启动 yasldr 数据迁移任务,设置 32 线程的 bulk load 模式 2、观察 yasldr.log 是否出现如下错
|
缓存 安全 Java
面试中的难题:线程异步执行后如何共享数据?
本文通过一个面试故事,详细讲解了Java中线程内部开启异步操作后如何安全地共享数据。介绍了异步操作的基本概念及常见实现方式(如CompletableFuture、ExecutorService),并重点探讨了volatile关键字、CountDownLatch和CompletableFuture等工具在线程间数据共享中的应用,帮助读者理解线程安全和内存可见性问题。通过这些方法,可以有效解决多线程环境下的数据共享挑战,提升编程效率和代码健壮性。
573 6
|
数据采集 存储 安全
Python爬虫实战:利用短效代理IP爬取京东母婴纸尿裤数据,多线程池并行处理方案详解
本文分享了一套结合青果网络短效代理IP和多线程池技术的电商数据爬取方案,针对京东母婴纸尿裤类目商品信息进行高效采集。通过动态代理IP规避访问限制,利用多线程提升抓取效率,同时确保数据采集的安全性和合法性。方案详细介绍了爬虫开发步骤、网页结构分析及代码实现,适用于大规模电商数据采集场景。
|
存储 Java easyexcel
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。

热门文章

最新文章