多线程应用:数据库百万级数据导入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工具类的封装:

