我的项目模仿一百万的数据导出,要求10s内实现全副数据导出,我的项目应用springboot + mysql + mybatis + poi。
我的项目核心思想 数据分页 + 线程池
采纳线程池和数据分页的起因:在于数据导出波及IO操作,不采纳线程池的话,串行耗时较长,同时数据量较大,不对数据进行分页解决,可能会产生内存溢出。

数据起源:百万数据插入

用户数据库:

CREATE TABLE `user` (  `id` int(11) NOT NULL,  `name` varchar(45) DEFAULT NULL,  `createdTime` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  `updatedTime` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  PRIMARY KEY (`id`),  KEY `index` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户测试表';

线程池数据量的设计:合理配置线程池数量
因为数据导出波及大量IO, 故线 程数量 = 2 * cpu核数

 final int nThreads = Runtime.getRuntime().availableProcessors(); ExecutorService pool = Executors.newFixedThreadPool(nThreads << 1);

同时,通过数据库查问语句增加where条件,缩小数据深度分页带来的性能损耗问题

<select id="selectPage" resultType="com.high.concurrency.currency02.domain.User">    select id, `name` from user where  id > #{param1} limit 0, #{param2}</select>

除此之外,数据库的优化,地址:MySQL外围参数优化

package com.high.concurrency.currency02.service.impl;import com.high.concurrency.currency02.domain.User;import com.high.concurrency.currency02.mapper.UserMapper;import com.high.concurrency.currency02.service.IUserService;import com.high.concurrency.currency02.util.ExcelUtil;import com.high.concurrency.currency02.util.PageUtil;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;@Servicepublic class UserServiceImpl implements IUserService {    @Autowired    private UserMapper userMapper;    @Override    public String exportData() {        // 获取可用的线程数        final int nThreads = Runtime.getRuntime().availableProcessors();        ExecutorService pool = Executors.newFixedThreadPool(nThreads << 1);        int pageSize = PageUtil.pageSize;        // 获取数据总量        Integer count = userMapper.getCount();        // 获取总页数        int totalPageCount= PageUtil.getTotalPageCount(count);        // 开始统计工夫        long start=System.currentTimeMillis();        int maxId = 0;        for(int currentPageNum = 0; currentPageNum < totalPageCount; currentPageNum++) {            List<User> userList = userMapper.selectPage(maxId, pageSize);            maxId = userList.get(userList.size() - 1).getId();            int finalCurrentPageNum = currentPageNum;            Runnable run = new Runnable() {                @Override                public void run() {                    ExcelUtil.createExcel(finalCurrentPageNum, userList);                    if(finalCurrentPageNum == (totalPageCount-1)){                        System.out.println("  export data to excel, it  has spent " +(System.currentTimeMillis()-start)+"  ms");                    }                }            };            pool.execute(run);        }        return "ok";    }}

操作成果如下:

代码地址:github