背景:较上一篇文章简单使用easyexcel已经过去一年半了,https://blog.csdn.net/qq_32447321/article/details/103793475 回想去年今天,完成了首次从老东家(就不说名字了,也的确不是BAT或TMD 咋好意思说自己在互联网公司待过)交接辞职,进入一个小创业团队,之后几个月 做了一个景区小火车购票系统直到11月份验收完,之后公司经营不行,收缩至合肥,11月开始到合肥,各种原因21年3月份回上海找工作,这一年下来实际的产出也就一套系统,一套方案设计,从需求-》设计-》原型-》开发-》交付-》验收-》运维 ,套路是全了深度就呵呵,就这;对比这20-》21年的收获,一是年龄涨了岁,二:熟悉了些微服务架构设计;就这;
展望:21-》22年,现公司每天早间新闻晨会贯彻“一切为了打仗”,警务自己“时刻准备着”,同事都百万年薪了,自己还一人吃饱就好状态,可不敢要,今天午休聊天同事修产假四个月,每天按公司平均工资发薪,四个月发了12w,卧槽,人均工资3w,太特么羡慕人了,不由得嘲讽自己,另同事说现在工资少点没关系,下家补过来,害,听起来也不是很开心,说这个呢就是说大家好好努力,思想是有边界的,你未知的幸福,不代表没有,提升自己不是负担,“大概是认知不同”阿巴阿巴
正事给忘了:这边是excel导出升级篇 ,背景:导出excel(一次 >3百万记录,十八字段,文件size: >100M),数据存储在mongodb,数据容量:< 100G
演变 导不出来 -》2min -> 30s;
talk is cheap ,show you code;具体
// 导出订单生成excel处理池
private ExecutorService processExportOrderExcelPool = new ThreadPoolExecutor(10, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(30),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
public BaseResultVo exportOrderInfo(BaseDto dto, StationInfoQueryBO bo, HttpServletResponse response) {
BaseResultVo vo = new BaseResultVo();
long s1 = System.currentTimeMillis();
try {
int ndrcNum = SyuserSyroleMapper.countUserIsNDRC(dto.getSyuserId());
DBObject sql = getMatchFields(dto, bo, ndrcNum);
long totalRowCount =mongoTemplate.getCollection("notificationChargeOrderInfo").count(sql);
//计算总数量,进行分批
System.out.println("导出总数totalRowCount|" + totalRowCount+"|count耗时:"+(System.currentTimeMillis()-s1));
logger.info("导出总数totalRowCount|" + totalRowCount+"|count耗时:"+(System.currentTimeMillis()-s1));
response.setHeader("Content-disposition", "attachment;filename=exportOrder.xlsx");
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), ExportOrder2Bo.class).build();
List<Future> headerflist = new ArrayList<>();
Long toIndex = Consts.PER_SHEET_ROW_COUNT_10W.longValue(); //数据100000条处理存一次
int sheetIndex = 0;//根据分批数创建对用数sheet
// 这里 指定文件
List<BlockingQueue> syncOrderLists = Collections.synchronizedList(new LinkedList<BlockingQueue>());
for (int i = 0; i < totalRowCount; i += Consts.PER_SHEET_ROW_COUNT_10W) {
if (i + Consts.PER_SHEET_ROW_COUNT_10W > totalRowCount) { //作用为toIndex最后没有100条数据则剩余几条newList中就装几条
toIndex = totalRowCount - i;
}
System.out.println("fori|"+Thread.currentThread().getName() +"|i:"+i);
// 并发执行
DBCollectionFindOptions copiedOptions = new DBCollectionFindOptions();
copiedOptions.limit(toIndex.intValue());//分页条数
copiedOptions.skip(i);//开始位置
copiedOptions.sort(new BasicDBObject("EndTime", -1));
headerflist.add(processExportOrderExcelPool.submit(new Runnable() {
@Override
public void run() {
try {
//// //根据条件查询订单(并行处理)
// long c1 = System.currentTimeMillis();
Iterable<DBObject> dbObjects = mongoTemplate.getCollection("notificationChargeOrderInfo").find(sql,copiedOptions);
// long c2 = System.currentTimeMillis();
// System.out.println(Thread.currentThread().getName()+"|执行sql耗时:"+(c2-c1));
BlockingQueue queue = new LinkedBlockingQueue(new LinkedList<ExportOrder2Bo>());
// List<ExportOrder2Bo> synchronizedList = new LinkedBlockingQueue(new LinkedList<ExportOrder2Bo>());//Collections.synchronizedList(new LinkedList<ExportOrder2Bo>());
// int i=0;
for (DBObject next:dbObjects) {
// i++;
asyncSetObjectCallback.submit(new Runnable() {
@Override
public void run() {
ExportOrder2Bo res = new ExportOrder2Bo();
res.setStartChargeSeq((String) next.get("StartChargeSeq"));
res.setCreatedTime((Date) next.get("CreatedTime"));
res.setEquipmentId((String) next.get("equipmentId"));
res.setConnectorID((String) next.get("ConnectorID"));
res.setStationName((String) next.get("stationName"));
res.setAreaName((String) next.get("areaName"));
res.setOrgName((String) next.get("orgName"));
res.setStartTime((Date) next.get("StartTime"));
res.setEndTime((Date) next.get("EndTime"));
res.setCostTime((Integer) next.get("costTime"));
res.setTotalPower((Double) next.get("TotalPower"));
res.setTotalElecMoney((Double) next.get("TotalElecMoney"));
res.setTotalSeviceMoney((Double) next.get("TotalSeviceMoney"));
res.setTotalMoney((Double) next.get("TotalMoney"));
// synchronizedList.add(res);
queue.add(res);
}
});
}
// long c3 = System.currentTimeMillis();
// logger.info(Thread.currentThread().getName() + "|mongo返回setList大小|"+queue.size()+"|mongo sql耗时|"+(c2-c1)+"|遍历耗时:"+(c3-c2));
syncOrderLists.add(queue);
} catch (Exception e) {
logger.error("--------exportOrderInfo error--------:");
e.printStackTrace();
}
}
}));
sheetIndex++;
}
// logger.info("for headerflist阻塞等待返回|");
//阻塞等待返回
try {
for (int i = 0; i < headerflist.size(); i++) {
// logger.info("headerflist阻塞等待返回|" + i);
headerflist.get(i).get();
// logger.info("headerflist get 阻塞等待返回|" + i);
if (syncOrderLists.size() >0) {
// long s3 = System.currentTimeMillis();
WriteSheet writeSheet = EasyExcel.writerSheet(i, "sheet" + i).head(ExportOrder2Bo.class).build();
List order=new ArrayList<ExportOrder2Bo>();
syncOrderLists.get(i).drainTo(order,100000);
excelWriter.write(order, writeSheet);
// long s4 = System.currentTimeMillis();
// logger.info("excelWriter SheetName:" + i + "|SheetNo: " + writeSheet.getSheetNo() + "|writerSheet 耗时|" + (s4 - s3));
}
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
System.out.println("--帮忙关闭流----");
} catch (Exception e) {
response.setStatus(400);
logger.error("--------process callback error--------:", e);
}
long s2 = System.currentTimeMillis();
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
} catch (Exception e) {
logger.info("exportOrderInfo error!");
response.setStatus(400);
e.printStackTrace();
}
long s2 = System.currentTimeMillis();
logger.info("导出订单耗时|" + (s2 - s1));
return vo;
}