极速响应Excel数据报表请求的一种方法
摘要
通过缓存和维护Excel Workbook实例,极速响应Excel数据报表请求。
这是一个真实的大数据“云计算”项目中的解决方案,在给定的时间和资源下,只有这种方法是最简单并且是可行的。
XX公司的需求
简单Excel报表:1个sheet。5秒内可以在界面展示。
复杂Excel报表:7个sheet。20秒内可以在界面展示。
并发响应:20个用户
详细介绍
每个sheet中有大量的Excel公式,如 F=E32-[35764%D1]*[DD]/[LD]。
每个单元格的值,需要后台从Mongodb数据库中取出并计算。
Web前端获得后台返回的数据,插入到Excel单元格中,然后Excel自动执行公式,然后将Excel完整地显示到界面中。
时间瓶颈
后台数据获取和数据计算的时间:
1个sheet要3-4s,7个sheet要10到20s。
前台展示剩下的时间:
1个sheet:1到2秒
7个sheet:0到10秒
读取Excel文件需要的时间
1个sheet:1s左右
7个sheet:2s左右
Excel文件构造成POI XSSFWorkbook对象
1个sheet:1s左右
7个sheet:7s左右
最初,我以为是IO有瓶颈,后来发现不是。主要是POI 构造XSSFWorkbook对象,需要花费很长时间。
XSSFWorkbook这可是一个比较大且复杂的数据结构,维护着一个Excel文档的所有信息。
(令人可气的是,测试机Linux服务器性能竟然还不如我的笔记本)
解决方案
考虑到并发请求最多也就是20,而且这只是一个Demo项目,因此“空间换时间”是可行的。
灵感来源:数据库连接池、对象池、缓存等都可以用来提高程序的性能。
最终方案:维护一份Workbook资源池。程序启动后,写一个定时器,监控资源池中的对象数量,达到资源下界的时候,就构造一些新的对象放进资源池中。
与数据库连接池等不同的是,Workbook资源池中的每一个XSSFWorkbook对象,只能使用一次。用完后,就必须从资源池中删除。
因为,XSSFWorkbook被使用后,很多状态都变了。
资源池代码结构
public class WorkbookPool {
private static int complexMinSize = TemplatePropertyReader.COMPLEX_MIN_SIZE;
// 复杂报表--最大缓存
private static int complexMaxSize = TemplatePropertyReader.COMPLEX_MAX_SIZE;
public WorkbookPool() {
}
public void init() {
simpleReportTimer();
complexReportTimer();
}
// 定时器任务---创建报表对象
private void simpleReportTimer() {
log.info("Simple Producter Timer Start...");
Timer producterTimer = new Timer();
// 在1秒后执行此任务,每次间隔1秒
producterTimer.schedule(new SimpleProducterTask(), 1000, 1000);
}
private void complexReportTimer() {
log.info("Complex Producter Timer Start...");
Timer complexProducterTimer = new Timer();
// 在1秒后执行此任务,每次间隔1秒
complexProducterTimer.schedule(new ComplexProducterTask(), 1000, 1000);
}
// 简单报表--定时器任务
class SimpleProducterTask extends TimerTask {
public void run() {
int simpleSize = simpleVector.size();
if (simpleSize <= simpleMinSize) {
int toBuildSize = simpleMaxSize - simpleSize;
log.info("before : simpleSize=" + simpleSize + ",toBuildSize=" + toBuildSize);
buildSimple(toBuildSize);
log.info("after : simpleSize=" + simpleVector.size());
}
}
}
// 复杂报表--定时器任务
class ComplexProducterTask extends TimerTask {
public void run() {
int complexSize = complexVector.size();
if (complexSize <= complexMinSize) {
int toBuildSize = complexMaxSize - complexSize;
log.info("before: complexSize=" + complexSize + ",toBuildSize=" + toBuildSize);
buildComplex(toBuildSize);
log.info("after: complexSize=" + complexVector.size());
}
}
}
}
启示
数据库连接池、对象池、缓存等很多程序设计中的概念,是存在着相似之处的。
学习和借鉴每一个成熟的概念和解决方案,能够产生更多的好方法。
活学活用,灵活解决实际工作中遇到的问题。
拒绝码农,谢绝书呆子。
相关阅读
ExcelToHtmlTable转换算法:将Excel转换成Html表格并展示(项目源码+详细注释+项目截图)
码农:客户是恶魔
原文参见:http://FansUnion.cn/articles/2851 小雷网(FansUnion.cn)
极速响应Excel数据报表请求的一种方法的更多相关文章
- SqlServer表EXCEL数据复制的另一种方法
一个.SqlServer表中的数据复制到excel 1.新建查询,用sql语句把表数据读出来 2.然后,选择数据,右键.复制(也能够点击连同标题复制),拷贝到记事本中(不然会乱码) 3.然后再把记事本 ...
- php发送post请求的三种方法示例
本文分享下php发送post请求的三种方法与示例代码,分别使用curl.file_get_content.fsocket来实现post提交数据,大家做个参考. php发送post请求的三种方法,分别使 ...
- php发送get、post请求的6种方法代码示例
本文主要展示了php发送get.post请求的6种方法的代码示例,分别为使用file_get_contents .fopen.fsockopen.curl来发送GET和POST请求,代码如下: 方法1 ...
- DataTable数据批量写入数据库三种方法比较
DataTable数据批量写入数据库三种方法比较 标签: it 分类: C#1) insert循环插入:2) sqldataadapter.update(dataset,tablename); ...
- 【MySQL】锁——查看当前数据库锁请求的三种方法 20
MySQL提供了查看当前数据库锁请求的三种方法:1. show full processlist命令 观察state和info列 2. show engine innodb status\G ...
- 手机数据抓包的N种方法
手机数据抓包的N种方法 - xia_xia的博客 - 博客频道 - CSDN.NEThttp://blog.csdn.net/xia_xia0919/article/details/50606137 ...
- DataTable 数据批量写入数据库三种方法比较
DataTable数据批量写入数据库三种方法比较 1) insert循环插入: 2) sqldataadapter.update(dataset,tablename); 3) sqlbul ...
- 使用命令行将Excel数据表导入Mysql中的方法小结
从Excel数据表导入MySQL,已经做过好几次了,但每次都会碰到各种问题:invalid utf8 character string, data too long, ...,浪费了不少时间 为了提高 ...
- 【MySQL笔记】Excel数据导入Mysql数据库的实现方法——Navicat
很多公司尤其有点年头的公司,财务业务部门的各种表单都是excel来做的表格,随着互联网的发展各种业务流程都电子化流程化了,再在茫茫多的文档中去查找某一个年份月份的报告是件相当枯燥的事,所以都在想办法将 ...
随机推荐
- SqlDependency C#代码监听数据库表的变化
SqlDependency提供了这样一种能力:当被监测的数据库中的数据发生变化时,SqlDependency会自动触发OnChange事件来通知应用程序,从而达到让系统自动更新数据(或缓存)的目的. ...
- 用jQuery设置多个css样式
$("#show_one").css({"position":"fixed","top":"0px" ...
- java上传文件工具类
这个是之前整理之前所学时与使用java向邮箱发送邮件一块找到的,一起贴出来供大家参考: import java.awt.image.BufferedImage; import java.io.File ...
- HDU-3065 病毒侵袭持续中 字符串问题 AC自动机
题目链接:https://cn.vjudge.net/problem/HDU-3065 题意 跟上一道题是几乎一模一样,这次是统计关键词的出现次数 一个相当坑的地方,注意多组样例 思路 套模版 改in ...
- HDU-4370 '0 or 1' 最短路 要考虑连通性
题目链接:https://cn.vjudge.net/problem/HDU-4370 题意 给一个矩阵C(nn),要我们找到一个矩阵X(nn),满足以下条件: X_{12}+X_{13}+...X_ ...
- redis.conf配置文件配置项解析
知识来源于 : https://blog.csdn.net/bsfz_2018/article/details/79061413[Redis在linux下的安装] daemonize:如需要在后台运行 ...
- yum-config-manager --add-repo=
[root@server0 yum.repos.d]# yum-config-manager --add-repo=ftp://192.168.31.121/centos7u4Loaded plugi ...
- Java 学习(11): 面向对象编程—继承(super,this)
Java 继承 what: 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为.子类从它的父类中继承可访问的数据域和方法,也 ...
- hpuoj--校赛--2015年的第一场雪(暴力)
问题 D: 感恩节KK专场--2015年的第一场雪 时间限制: 1 Sec 内存限制: 128 MB 提交: 865 解决: 76 [提交][状态][讨论版] 题目描述 下雪了,KK学长站在三教门 ...
- Python: PS 滤镜--碎片特效
本文用 Python 实现 PS 滤镜中的碎片特效,这个特效简单来说就是将图像在 上,下,左,右 四个方向做平移,然后将四个方向的平移的图像叠加起来做平均.具体的效果图可以参考之前的博客 http:/ ...