EasyExcel读取所有sheet(doReadAll)报BatchUpdateException: Duplicate entry

发布时间 2023-10-23 22:53:49作者: CassieProcess

报错截图

 

 

原因:监听器保存数据时,但是没有重置缓存数据,导致读取第二个sheet的时候,缓存里存的数据还包含上一个或多个sheet的数据。每个sheet读取完毕后调用一次doAfterAllAnalysed。在doAfterAllAnalysed方法调用批量插入后,需要 清除缓存数据

cacheDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
 1 package com.example.excel.listener;
 2 
 3 import com.alibaba.excel.context.AnalysisContext;
 4 import com.alibaba.excel.read.listener.ReadListener;
 5 import com.alibaba.excel.util.ListUtils;
 6 import com.alibaba.fastjson.JSON;
 7 import com.example.excel.entity.ImportExcel;
 8 import com.example.excel.service.ImportService;
 9 import com.example.excel.service.impl.ImportServiceImpl;
10 import lombok.extern.slf4j.Slf4j;
11 
12 import java.util.List;
13 
14 /**
15  * <p>
16  *
17  * </p >
18  *
19  * @author Heqq
20  */
21 // 有个很重要的点 ImportExcelListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
22 @Slf4j
23 public class ImportExcelListener implements ReadListener<ImportExcel> {
24 
25 
26     /**
27      * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
28      */
29     private static final int BATCH_COUNT = 100;
30 
31     /**
32      * 缓存的数据
33      */
34     private List<ImportExcel> cacheDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
35 
36     /**
37      * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
38      */
39     private ImportService importService;
40 
41     /**
42      * 这里是importService,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
43      */
44     public ImportExcelListener() {
45         // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
46         importService = new ImportServiceImpl();
47     }
48 
49     /**
50      * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
51      *
52      * @param importService
53      */
54     public ImportExcelListener(ImportService importService) {
55         this.importService = importService;
56     }
57 
58     /**
59      * 这个每一条数据解析都会来调用
60      *
61      * @param importExcel
62      * @param analysisContext
63      */
64     @Override
65     public void invoke(ImportExcel importExcel, AnalysisContext analysisContext) {
66         log.info("解析到一条数据:{}", JSON.toJSONString(importExcel));
67         cacheDataList.add(importExcel);
68         // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
69         if (cacheDataList.size() >= BATCH_COUNT) {
70             saveData();
71             // 存储完成清理 list
72             cacheDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
73         }
74     }
75 
76     /**
77      * 所有数据解析完成了 都会来调用
78      *
79      * @param analysisContext
80      */
81     @Override
82     public void doAfterAllAnalysed(AnalysisContext analysisContext) {
83         // 这里也要保存数据,确保最后遗留的数据也存储到数据库
84         saveData();
85         cacheDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
86         log.info("所有数据解析完成!");
87     }
88 
89     /**
90      * 加上存储数据库
91      */
92     public void saveData() {
93         log.info("{}条数据,开始存储数据库!", cacheDataList.size());
94         importService.saveBatch(cacheDataList);
95         log.info("存储数据成功!");
96     }
97 }