首页 > 基础资料 博客日记
Java 使用 EasyExcel 实现百万级数据的秒级导出
2025-01-01 15:00:07基础资料围观47次
在数据处理领域,导出大数据量的 Excel 文件是一个常见的需求,尤其是在企业级应用中。无论是报表导出、数据分析,还是系统日志生成,Excel 文件作为一种通用的数据交换格式,广泛应用于各行各业。然而,随着数据量的不断增大,传统的导出方式往往会面临性能瓶颈,导致内存溢出或导出时间过长。如何高效处理百万级数据的导出,成为了一个需要解决的问题。
在 Java 中,EasyExcel 是一个高效、简便的 Excel 操作库,相比传统的 Apache POI,EasyExcel 通过减少内存占用和优化性能,提供了更适合大数据量处理的解决方案。本文将介绍如何使用 EasyExcel 高效导出百万级数据。
为什么选择 EasyExcel
在处理大数据量的 Excel 导出时,选择合适的工具库至关重要。与传统的 Apache POI 相比,EasyExcel 具有以下几个优点:
- 内存占用低:EasyExcel 使用了流式 API,避免了将整个 Excel 文件加载到内存中,这样可以大大降低内存的消耗。
- 高效性能:通过减少 Java 对象和 Excel 的频繁转换,EasyExcel 提供了更高效的性能,特别适合处理大量数据。
- 简单易用:EasyExcel 提供了简洁的 API,能够快速实现各种常见的 Excel 操作,降低了开发的复杂度。
环境准备
在开始之前,你需要先将 EasyExcel 添加到项目中。可以使用 Maven 或 Gradle 来引入 EasyExcel。
Maven 依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version> <!-- 请根据需要选择最新版本 -->
</dependency>
主要代码逻辑 :
dto:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value="excel_table",autoResultMap = true)
public class ExcelTable {
@TableId(type = IdType.AUTO)
private int id;
@ExcelProperty(index = 1) // 'name' 的索引为 1
private String name;
@ExcelProperty(index = 2) // 'sex' 的索引为 2
private String sex;
@ExcelProperty(index = 3) // 'age' 的索引为 3
private Integer age;
@ExcelProperty(index = 4) // 'address' 的索引为 4
private String address;
@ExcelProperty(index = 5) // 'email' 的索引为 5
private String email;
@ExcelProperty(index = 6) // 'phone' 的索引为 6
private String phone;
}
mapper:
@Mapper
public interface ExcelTableMapper extends BaseMapper<ExcelTable> {
/**
* 批量插入 ExcelTable 数据
* @param excelTables ExcelTable 对象列表
* @return 插入成功的记录数
*/
@Insert({
"<script>",
"INSERT INTO excel_table (name, sex, age, address, email, phone) VALUES",
"<foreach collection='list' item='item' separator=','>",
"(#{item.name}, #{item.sex}, #{item.age}, #{item.address}, #{item.email}, #{item.phone})",
"</foreach>",
"</script>"
})
int batchInsert(List<ExcelTable> excelTables);
}
监听器:
@Slf4j
@Service
public class ExcelTableListener extends AnalysisEventListener<ExcelTable> {
/*单次处理条数*/
private final static int BATCH_COUNT = 1000000;
// 创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(8); // 创建 4 个线程进行并行处理
private final List successList = new ArrayList<ExcelTable>();
// 批量存储数据的容器(例如,你可以使用一个 List)
private ExcelTableMapper excelTableMapper;
public ExcelTableListener(ExcelTableMapper excelTableMapper) {
this.excelTableMapper = excelTableMapper;
}
// 每读取一行数据,就会调用这个方法
@Override
public void invoke(ExcelTable excelTable, AnalysisContext context) {
successList.add(excelTable);
if(successList.size() >= BATCH_COUNT){
log.info("读取数据:{}", successList.size());
saveData(successList);
successList.clear();
}
}
// 读取完成后的处理方法(在 Excel 文件全部读取完之后调用)
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 你可以在这里执行一些收尾操作,通常用于关闭流或者进行批量保存等操作
saveData(successList);
successList.clear();
}
/**
* 采用多线程读取数据
*/
private void saveData(List<ExcelTable> batchList) {
//每两千条数据,进行一次批量插入
log.info("-----开始进行数据的入库");
List<List<ExcelTable>> partition = ListUtils.partition(batchList, 100000);
CountDownLatch countDownLatch = new CountDownLatch(partition.size());
for (List<ExcelTable> excelTables : partition) {
executorService.execute(()->{
log.info("-------进行数据的插入");
excelTableMapper.batchInsert(excelTables);
countDownLatch.countDown();
});
}
// 等待所有线程执行完
try {
countDownLatch.await();
} catch (Exception e) {
log.error("等待所有线程执行完异常,e:{}", e.getMessage(), e);
}
log.info("-------入库结束");
}
}
测试方法:
@Autowired
private ExcelTableMapper excelTableMapper;
@Test
public void excelToDb(){
String fileName = "D:\\home\\aaaac.XLSX";
//记录开始读取Excel时间,也是导入程序开始时间
long startReadTime = System.currentTimeMillis();
System.out.println("------开始时间:" + startReadTime + "ms------");
//读取所有Sheet的数据.每次读完一个Sheet就会调用这个方法
// EasyExcel.read(fileName, new ExcelTableListener(excelTableMapper)).doReadAll();
EasyExcel.read(fileName, ExcelTable.class, new ExcelTableListener(excelTableMapper))
.doReadAll();
long endReadTime = System.currentTimeMillis();
System.out.println("------结束时间:" + endReadTime + "ms------");
System.out.println("------导出数据总用时:"+(endReadTime-startReadTime)/1000);
}
运行结果:总用时154秒
我们导出的数据量是:四百多万条
总结
使用 EasyExcel 导出百万级数据时,关键在于如何优化内存使用和性能。通过以下几种方式,我们可以有效地解决大数据量导出的挑战:
- 使用流式写入:避免一次性将所有数据加载到内存中,减少内存占用。
- 分批写入:将数据分批处理,每次写入小部分数据,避免内存溢出。
- 多线程优化:在导出过程中使用多线程并行处理数据,提高导出速度。
EasyExcel 提供了高效且易于使用的 API,使得大数据量的 Excel 导出变得简单且高效。在实际开发中,结合这些技术,可以轻松应对百万级数据的导出任务。
点点关注,点点赞呀,持续更新有用的知识............
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: