大数据量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万数据,时间大概半分钟多一点,速度还是很快的。这里应该是会涉及到数据库连接池的问题,需要限制连接的数量,不能将资源都分给文件上传。