极速响应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来做的表格,随着互联网的发展各种业务流程都电子化流程化了,再在茫茫多的文档中去查找某一个年份月份的报告是件相当枯燥的事,所以都在想办法将 ...
随机推荐
- .net垃圾回收-原理浅析
本文引自:http://www.cnblogs.com/wilber2013/p/4357910.html 在开发.NET程序过程中,由于CLR中的垃圾回收(garbage collection)机制 ...
- CentOS 安装 PHP7
下载地址:http://php.net/downloads.php 上传目录:/usr/local/src 安装目录:/usr/local/php ## 参考资料 PHP官网: http://php. ...
- MyBatis数据持久化(五)数据源配置优化
在前面的教程中,我们把数据库的驱动.用户名.密码等配置项全部写在 SqlMapConfig.xml中: <dataSource type="POOLED"> <p ...
- RabbitMq笔记(2)
今天收获不少,记个笔记. namespace RabbitMQTest { class Program { static void Main(string[] args) { Consumer(); ...
- out ref params
out的使用 out 能够使我们的函数返回多个类型的值,不再受返回类型的设置: 就是相当于在方法里不仅仅给了一个返回值,被out修饰的参数的值也能带出去: 所以就是说,在方法体内被out修饰的参数,都 ...
- hiho1116 - 数据结构 线段树(区间合并)
题目链接 现在有一个有n个元素的数组a1, a2, ..., an. 记f(i, j) = ai * ai+1 * ... * aj. 初始时,a1 = a2 = ... = an = 0,每次我会修 ...
- windows2008 虚拟机64位的操作系统安装32位的应用程序
64位的操作系统安装32位的应用程序: 安装成功但是使用有问题 报错: 最终解决: 在一台物理机的win7上面安装该软件. 然后把安装好的文件全部拷贝到win2008虚拟机上面 启动,使用 多ok了! ...
- 贰、js的基础(三)数组
JS中数组的操作 1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长 ...
- css兼容性问题总结
DIV+CSS设计IE6.IE7.FF 兼容性 DIV+CSS网页布局这是一种趋势,我也开始顺应这股趋势了,不过在使用DIV+CSS网站设计的时候,应该注意css样式兼容不同浏览器问题,特别是对完全使 ...
- POJ 3134 Power Calculus (迭代剪枝搜索)
题目大意:略 题目里所有的运算都是幂运算,所以转化成指数的加减 由于搜索层数不会超过$2*log$层,所以用一个栈存储哪些数已经被组合出来了,不必暴力枚举哪些数已经被搜出来了 然后跑$iddfs$就行 ...