多线程批量插入数据

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在面试过程中我们经常会被问到多线程的问题。但是在实际工作过程中可能使用的场景不是特别多,在这边给大家提供一个多线程使用的实际场景案例。


一、多线程使用背景

在目前参与的智慧大屏项目中,部分初始数据需要通过 Excel 导入到数据库。最大的一个 Excel 表中有约 100 万条数据,单线程批量插入的时间消耗超过两个小时,这显然不可接受。因此,我们打算通过多线程插入的方式来优化代码。

二、代码实现

1.单线程插入

代码如下:

@Slf4j
public class HouseImportListener extends AnalysisEventListener<HouseImportVo> implements ExcelListener<HouseImportVo> {
    private final HouseReportMapper houseReportMapper;

    private List<HouseReport> dataList = new ArrayList<>();

    public HouseImportListener() {
        this.houseReportMapper = SpringUtils.getBean(HouseReportMapper.class);
    }
	
    @Override
    public void invoke(HouseImportVo houseImportVo, AnalysisContext context) {

        try {
            HouseReport houseReport=new HouseReport();
            houseReport.setContractNumber(houseImportVo.getContractNumber());
            houseReport.setLocation(houseImportVo.getLocation());
            houseReport.setArea(houseImportVo.getArea());
            houseReport.setType(houseImportVo.getType());
            houseReport.setBank(houseImportVo.getBank());
            dataList.add(houseReport);
        } catch (Exception e) {
            log.error("数据转换出错:{}",e.getMessage());
        }
    }
	
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        houseReportMapper.insertBatch(dataList);
    }
	
    @Override
    public ExcelResult<HouseImportVo> getExcelResult() {
        return new ExcelResult<>() {

            @Override
            public String getAnalysis() {
                return "插入数据完成!";
            }

            @Override
            public List<HouseImportVo> getList() {
                return null;
            }

            @Override
            public List<String> getErrorList() {
                return null;
            }
        };
    }
}

2.多线程插入

代码如下(示例):

@Override
public void doAfterAllAnalysed(AnalysisContext context) {
       //大于2000使用多线程插入
       int size = dataList.size();
       if(size>2000){
	       //每批插入1000条
           int num=1000;
           //计算总批次
           int batch=(size+num-1)/num;
           /*
           * 线程池,20代表核心线程数,100代表最大线程数,10代表线程空间时间
			*/
           ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(batch));
           //分批循环插入       
           for (int i = 0; i < batch; i++) {
               int start=num*i;
               int end=Math.min((i+1)*num,size);
               List<HouseReport> threadData = dataList.subList(start, end);
               Runnable task=()->{
                   houseReportMapper.insertBatch(threadData);
               };
               threadPoolExecutor.execute(task);
           }
       }else {
           houseReportMapper.insertBatch(dataList);
       }
   }

总结

通过将插入方式修改为多线程之后,插入效率显著提供,可以在20分钟内将100W条数据读取并插入到数据库中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值