多线程应用:数据库百万级数据导入Excel表格

废话不说,先看疗效

数据库数据:4194294条

实现目标:DB ——> Excel表格

导出结果:

动手之前,先避坑

1. jdbc读取百万条数据出现内存溢出OOM。 因为mysql jdbc默认把select的所有结果全部取回,放到内存中,如果是要遍历很大的表,则可能把内存撑爆。这是查询后数据存到内存时,内存不足引起的。

通过分页查询来优化

2. 单线程执行一次性的查询上百万条数据JVM需要同时间创建上百万个对象也会造成OOM。这时JVM内存不足引起的。

通过使用多线程来优化。

思路:

线程池技术 + CountDownLatch + 分页查询 + 动态生成Excel工具类

工具类封装链接放在文章最下方,需要请点击传送门~

==================================核心==================================

代码详解

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NewsApplication.class)
public class ImportTest {

    @Autowired
    private ThreadPoolTaskExecutor executor;

    @Autowired
    private INewsInfoService iNewsInfoService;

    /**
     * 测试百万条数据导入
     */
    @Test
    public void testMillionDataImport() throws Exception {

        //数据库总记录数,本机是400多万条
        int count = iNewsInfoService.count();

        //每次一万条
        int limit = 10000;

        //分段次数
        int cycles = count / limit;

        //使一个线程等待其他线程各自执行完毕后再执行
        CountDownLatch countDownLatch = new CountDownLatch(cycles);

        for (int i = 0; i < cycles; i++) {

            //每一段的起始坐标
            Integer idx = i * limit;
            log.info("idx: {}", idx);

            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        //分页查询列表数据
                        List<NewsInfo> infos = iNewsInfoService.listData(idx, limit);
                        //存入Excel
                        PoiUtil.createDynamicListExcel(infos);
                        //减少一个容量
                        countDownLatch.countDown();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };

            //把任务丢给线程池调度执行
            executor.execute(runnable);
        }

        try {
            //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

传送门

关于如何使用反射技术实现动态传入对象生成Excel工具类的封装:

经验分享 程序员 微信小程序 职场和发展