EasyExcel批量导入数据

EasyExcel批量导入数据

easyExcel官网:https://easyexcel.opensource.alibaba.com/

一. 导入pom依赖:

```<!--excel导入导出-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

二. 监听器(用来解析excel文件内容)

@Slf4j
@Component
public class ExcelListener implements ReadListener<UserVo> {

    //日志
    private static final Log logger = LogFactory.getLog(ExcelListener.class);

    private UserService userService;

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 10000;

    /**
     * 缓存的数据
     */
    private List<UserVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    /**
     * 多线程缓存数据,需要不会被多线程影响的变量
     */
    private ThreadLocal<ArrayList<UserVo>> cachedDataListAsync = ThreadLocal.withInitial(ArrayList::new);

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public ExcelListener(UserService userService) {
        this.userService = userService;
    }


    @Override
    public void invoke(UserVo userVo, AnalysisContext analysisContext) {
        //解析多条数据,统一执行
        log.info("解析到一条数据(多线程):{}", JSON.toJSONString(userVo));
        cachedDataListAsync.get().add(userVo);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (cachedDataListAsync.get().size() >= BATCH_COUNT) {
            //单线程插入
            saveData();
        }


    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        //数据解析完,执行方法
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }


    public void saveData() {
        log.info("{}条数据,开始存储数据库!");
        long wasteTimeStart = System.currentTimeMillis();
        System.out.println("开始时间" + wasteTimeStart);

        //mybatis-plus批量保存(mybatis-plus的批量保存)
        userService.saveBatch(cachedDataListAsync.get(), cachedDataListAsync.get().size());
        cachedDataListAsync.get().clear();

        long wasteTimeEnd = System.currentTimeMillis();
        System.out.println("结束时间" + wasteTimeEnd);
        log.info("存储数据库成功!保存数据库时间:" + (wasteTimeEnd - wasteTimeStart));
    }
}

三. Controller

@Slf4j
@RestController
@RequestMapping("/user")
public class UserConroller {

    @Autowired
    private ExcelListener excelListener;

    //创建20个线程的线程池
    private ExecutorService executorService = Executors.newFixedThreadPool(20);

    /**
     * excel文件上传(多线程处理)
     *
     * @param file
     * @return
     */
    @PostMapping("/uploadExcelAsync")
    public void uploadFileByEasyExcelUserInfoAsync(@RequestParam("file") MultipartFile file) {
        //开启20个线程分别导入
        ArrayList<Callable<Object>> tasks = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            int num = i;
            tasks.add(() -> {
                EasyExcel.read(file.getInputStream(), UserVo.class, excelListener).sheet(num).doRead();
                return null;
            });
        }
        try {
            // 调用该方法的线程会阻塞,直到tasks全部执行完成(正常完成/异常退出)
            executorService.invokeAll(tasks);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

四. services

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserVo> implements UserService {
//调用mybatis-plus中的saveBatch,批量保存(集成mybatis-plus,然后继承ServiceImpl直接用)
}

五.Vo`

@Data
@TableName("user")
public class UserVo implements Serializable {
    @ExcelProperty(value = "id")
    private Integer id;
    @ExcelProperty(value = "姓名")
    private String mingzi;

    //@ExcelProperty(value = "性别",converter = SexTypeConvert.class)
    @ExcelProperty(value = "性别")
    private String sex;
    @ExcelProperty(value = "地址")
    private String address;
    @ExcelProperty(value = "国家")
    private String country;
    @ExcelProperty(value = "民族")
    private String minzu;
    @ExcelProperty(value = "电话")
    private String phone;
    @ExcelProperty(value = "生日",format = "yyyy-MM-dd")
    private Date birthday;
    @ExcelProperty(value = "录入时间",format = "yyyy-MM-dd")
    private Date createtime;
}

六. 生成测试数据

#删除存储过程
DROP PROCEDURE IF EXISTS insert_while;

#创建存储过程
delimiter //
	CREATE PROCEDURE insert_while()
	BEGIN
		DECLARE i INT;
		DECLARE tempUUID text;
		SET i = 1;
		WHILE i <= 100000 DO
			INSERT INTO `user`(`mingzi`, `address`, `birthday`, `country`, `phone`, `minzu`, `sex`, `createtime`)
			VALUES(CONCAT('外包', i),"中国上海", now(), '中国', '15263852536',"汉",i%2,now());
			SET i = i + 1;
		END WHILE;
	END //
delimiter;

#执行存储过程
CALL insert_while();

#删除存储过程
DROP PROCEDURE IF EXISTS insert_while;


EasyExcel是阿里巴巴开源的一款Java库,用于简化大数据量的Excel文件导入和导出操作。在进行批量导入时,如果出现错误数据,可能是由于以下几个原因: 1. 数据格式不匹配:Excel文件中的数据格式(如日期、数字或字符串)可能与你定义的数据字段类型不匹配,导致解析失败。 2. 数据校验规则:如果你在代码中设置了数据验证规则,比如邮箱格式、电话号码格式等,不符合规则的值会引发错误。 3. 行列结构问题:如果Excel文件的结构与你的数据模型不一致,比如缺少字段或多了字段,都会导致导入失败。 4. 文件损坏或编码问题:Excel文件可能存在损坏或使用了非UTF-8等不支持的编码,这会导致解析过程出错。 5. 限制或异常:EasyExcel在处理大量数据时,可能会因为内存限制或其他内部异常而抛出错误。 为了解决这些问题,你可以尝试以下步骤: - **检查数据**:预览Excel文件的内容,确保数据格式正确且没有缺失或冗余的数据。 - **配置映射**:调整EasyExcel的列映射,确保每个字段都对应正确的字段名和数据类型。 - **异常处理**:添加适当的异常处理代码,捕获并记录错误,以便于定位问题。 - **分批导入**:如果数据量非常大,可以考虑分批导入,减少单次加载的数据量。 - **检查版本**:确认使用的EasyExcel版本是否兼容你的项目需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值