EasyExcel+多线程实现大数据量

发布时间:2024年01月11日

文章目录

概要

整体架构流程

技术细节

小结


概要

大数据量Excel文件导入数据库

整体架构流程

使用多线程+EsayExcel+MyBatis批量导入实现大数据量Excel文件导入数据库

技术细节

EasyExcel

1、引入依赖

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>easyexcel</artifactId>
   <version>3.3.2</version>
</dependency>

?版本自己看着定。

2、实现代码,基础版本

DAO

public interface MallUserDao {

        int insertBatch(@Param("entities") List<MallUser> entities);

}

?Mapper

   <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
        insert into mall_user(user_name, user_age, user_sex, phone_number, user_mail, user_address, create_date, update_date)
        values
        <foreach collection="entities" item="entity" separator=",">
        (#{entity.userName}, #{entity.userAge}, #{entity.userSex}, #{entity.phoneNumber}, #{entity.userMail}, #{entity.userAddress}, #{entity.createDate}, #{entity.updateDate})
        </foreach>
    </insert>

?Entity

public class MallUser implements Serializable {
    private static final long serialVersionUID = 601074948288676334L;

    @ExcelIgnore
    private Integer id;
    @ExcelProperty("姓名")
    private String userName;
    @ExcelProperty("年龄")
    private String userAge;
    @ExcelProperty("性别")
    private String userSex;
    @ExcelProperty("电话")
    private String phoneNumber;
    @ExcelProperty("邮箱")
    private String userMail;
    @ExcelProperty("地址")
    private String userAddress;
    @ExcelIgnore
    private Date createDate;
    @ExcelIgnore
    private Date updateDate;


    //自己加一下get/set方法,太多了影响观文效果

}

?service

?

@Slf4j
@Service
public class ExcelImportServiceImpl implements ExcelImportService {

    @Resource
    private MallUserDao mallUserDao;


    private static final int BATCH_COUNT = 1000;

    @Override
    public void doImport() {
        log.info("进入导入逻辑");
        //需要读取的sheet数量
        int numberOfSheets = 5;
        String fileName = "item-service/src/main/resources/file/mallUser.xlsx";

        ExecutorService executorService = Executors.newFixedThreadPool(numberOfSheets);

        for (int sheetNo = 0; sheetNo < numberOfSheets; sheetNo++){
            int sheetNumber = sheetNo;
            executorService.submit(()->{
                EasyExcel.read(fileName, MallUser.class, new PageReadListener<MallUser>(dataList -> { //这里的dataList 数据量是根据BATCH_COUNT参数的大小定的
                    List cacheList = new ArrayList();
                  
                    for (MallUser mallUser : dataList) { //for循环里面可以对数据进行校验和处理
                        //数据校验
                        //设置数据的创建时间和更新时间
                        Date date = new Date();
                        mallUser.setCreateDate(date);
                        mallUser.setUpdateDate(date);
                        cacheList.add(mallUser);
                    }
                    mallUserDao.insertBatch(cacheList);//批量入库
                },BATCH_COUNT)).sheet(sheetNumber).doRead(); //这里下面这个BATCH_COUNT是设置每次读取sheet页的多少条数据到内存
                
            });
        }

        executorService.shutdown();//关闭线程池

        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

     
    }
}

最开始的时候有两个难点:

? 1、多线程读取问题
? 2、批量入库问题,如果最后一批数据不足临界值怎么解决

对于第一点,EasyExcel自动实现了,sheetNumber就是读取的每一页的页数。

第二点其实也不用担心,只需要把BATCH_COUNT参数传进new PageReadListener()的构造函数就可以了,这样每次读取数据到内存中的数量就是BATCH_COUNT条,默认BATCH_COUNT=100,我这里设置成一千,最后不足一千也会读取完然后入库。

小结

? ? ? ? 在没有任何校验逻辑的情况下,导入了90万数据,时间大概半分钟多一点,速度还是很快的。这里应该是会涉及到数据库连接池的问题,需要限制连接的数量,不能将资源都分给文件上传。

文章来源:https://blog.csdn.net/qq_42251944/article/details/135518279
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。