1.开发背景
在web项目中,经常会需要查询数据导出excel,以前比较常见的就是用poi。使用poi的时候也有两种方式,一种就是直接将集合一次性导出为excel,还有一种是分批次追加的方式适合数据量较大的情况。poi支持xls和xlsx,使用2003版本的只支持6万多行以下的数据量,使用2007版本的支持百万行。但是呢,当数据量大了之后这种方式却非常耗内存和时间。
接触了etl之后就想着用kettle来做导数据,经过测试是完全可行的。几十万行,一百万行都能快速导出来,代码也非常简单。
 
2.kettle相关maven依赖如下
  1. <dependency>
  2. <groupId>org.apache.commons</groupId>
  3. <artifactId>commons-vfs2</artifactId>
  4. <version>2.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.scannotation</groupId>
  8. <artifactId>scannotation</artifactId>
  9. <version>1.0.3</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>dom4j</groupId>
  13. <artifactId>dom4j</artifactId>
  14. <version>1.6.1</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>pentaho-kettle</groupId>
  18. <artifactId>kettle-vfs</artifactId>
  19. <version>5.2.0.0</version>
  20. <classifier>pentaho</classifier>
  21. </dependency>
  22. <dependency>
  23. <groupId>pentaho-kettle</groupId>
  24. <artifactId>kettle-engine</artifactId>
  25. <version>5.2.0.0</version>
  26. </dependency>
  27. <dependency>
  28. <groupId>pentaho-kettle</groupId>
  29. <artifactId>kettle-core</artifactId>
  30. <version>5.2.0.0</version>
  31. </dependency>

Maven依赖

仓库如果没有kettle的jar包,可以先现在下来再上传到maven仓库

3.ktr文件:如以下附件下载链接

 由于博客园不支持ktr路径的文件上传,所以我将它保存为xml文件,使用时将xml后缀去掉用ktr后缀就可以 了,该转换就是查询,导出为excel两个组件,如图所示:

这里用到一个输入和excel输出,里面配置的参数:

查询语句: ${exec_select_sql}、

文件名称:${filepath}、

sheet名称:${sheetname}

 
4.调用ktr
  1. /**
  2. * @功能描述: java调用Kettle导出的KTR,方法调用成功后,通过filepath参数获取文件<br><font color="red">该程序已经指定数据源</font>
  3. * @创建作者: ***
  4. * @创建日期: 2016年11月1日 下午7:50:57
  5. * @param exec_select_sql:可执行的SELECT语句(案例:SELECT username '名称',userName '员工名称',ID 'ID' FROM `User`;)
  6. * @param filepath:保存的文件名称,不含后缀,后缀统一xlsx(案例:C:\\test)
  7. * @param sheetname:文件中的sheet名称(默认:下载)
  8. * @return
  9. */
  10. public static boolean exportXlsx(String exec_select_sql, String filepath, String sheetname) {
  11. if(StringUtils.isEmpty(exec_select_sql)||StringUtils.isEmpty(filepath))
  12. return false;
  13. Trans trans = null;
  14. if(StringUtils.isEmpty(sheetname)) sheetname = "下载";
  15. String uuid = UUID.randomUUID().toString();
  16. logger_info.info("KettleUtil@exportXlsx:"+uuid+" {exec_select_sql:"+exec_select_sql+",filepath:"+filepath+",sheetname:"+sheetname+"}");
  17. try {
  18. String root_path = getPathMethod();
  19. // 初始化
  20. String fName = root_path+"export_xlsx.ktr";
  21. // 转换元对象
  22. KettleEnvironment.init();// 初始化
  23. EnvUtil.environmentInit();
  24. TransMeta transMeta = new TransMeta(fName);
  25. // 转换
  26. trans = new Trans(transMeta);
  27. // 执行转换
  28. trans.setVariable("exec_select_sql", exec_select_sql);
  29. trans.setVariable("filepath", filepath);
  30. trans.setVariable("sheetname", sheetname);
  31. trans.execute(null);
  32. // 等待转换执行结束
  33. trans.waitUntilFinished();
  34. // 抛出异常
  35. if (trans.getErrors() > 0) {
  36. logger_info.info("KettleUtil@exportXlsx:"+uuid+" 执行失败");
  37. }else{
  38. logger_info.info("KettleUtil@exportXlsx:"+uuid+" 执行成功");
  39. }
  40. return true;
  41. } catch (Exception e) {
  42. logger_error.error("KettleUtil@exportXlsx:"+uuid, e);
  43. return false;
  44. }
  45. }
  46.  
  47. /**
  48. * @功能描述: 获取编译目录
  49. * @创建作者: ***
  50. * @创建日期: 2016年11月1日 下午7:59:13
  51. * @return
  52. */
  53. private static String getPathMethod(){
  54. URL url= KettleUtil.class.getClassLoader().getResource("");
  55. String p = url.getPath();
  56. try {
  57. p=URLDecoder.decode(p, "UTF-8");
  58. } catch (UnsupportedEncodingException e) {
  59. logger_error.error("KettleUtil@getPathMethod:", e);
  60. }
  61. return p;
  62. }

java调用kettle转换

5.测试导出方法

web项目中的测试

@RequestMapping("/kettle")
public Object kettle(int rows, String sql) {
    String sqlLimit = sql + "LIMIT "+rows;
    String fullName = "/home/admin/DataPlatform/temp"+ "/kettle"+uuid;
    this.kettleExportExcel(sqlLimit, fullName, "kettle");
    return null;
}
也可以用main函数或junit测试
 
6.打印执行信息,也可以直接在程序里面加
  1. @Component
  2. @Aspect
  3. public class ControllerAspect {
  4. private static Logger logger_info = Logger.getLogger("api-info");
  5. private static Logger logger_error = Logger.getLogger("api-error");
  6. /**
  7. * 切面
  8. */
  9. private final String POINT_CUT = "execution(* com.demo.controller.*.*(..))";
  10. @Pointcut(POINT_CUT)
  11. private void pointcut() {
  12. }
  13. @AfterThrowing(value = POINT_CUT, throwing = "e")
  14. public void afterThrowing(Throwable e) {
  15. logger_error.error("afterThrowing: " + e.getMessage(), e);
  16. }
  17. /**
  18. * @功能描述: 打印Controller方法的执行时间
  19. * @创建日期: 2016年11月2日 上午11:44:11
  20. * @param proceedingJoinPoint
  21. * @return
  22. * @throws Throwable
  23. */
  24. @Around(value = POINT_CUT)
  25. public Object around(ProceedingJoinPoint proceedingJoinPoint)
  26. throws Throwable {
  27. String className = proceedingJoinPoint.getTarget().getClass().getName();
  28. String methodName = proceedingJoinPoint.getSignature().getName();
  29. Long begin = System.currentTimeMillis();
  30. Long beginMemory = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
  31. StringBuilder log = new StringBuilder(className+"@"+methodName);
  32. Object result = null;
  33. try {
  34. result = proceedingJoinPoint.proceed();
  35. } catch (Exception e) {
  36. logger_error.error(log + e.getMessage(), e);
  37. }
  38. Long end = System.currentTimeMillis();
  39. Long endMemory = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
  40. log.append(" 执行时间: ").append(end - begin).append("ms");
  41. log.append(" 消耗内存: ").append(endMemory - beginMemory).append("Byte");
  42. logger_info.info(log);
  43. return result;
  44. }
  45. }

7.执行结果

* 导出10w行记录

执行时间: 1133ms

执行时间: 1082ms

执行时间: 1096ms

* 导出100w行记录

执行时间: 39784ms

执行时间: 8566ms

执行时间: 8622ms 
* Excel 2007行数极限 1048575 执行时间: 9686ms

第一次导数据要加载kettle组件运行稍慢,后面几次再导数据速度就飞快了,更多结果有兴趣的可以去试试。

仅供参考,不足之处还请见谅,欢迎指正!转载请标明出处。如有疑问,欢迎评论或者联系我邮箱1034570286@qq.com

 

大量数据快速导出的解决方案-Kettle的更多相关文章

  1. Oracle大规模数据快速导出文本文件

    哈喽,前几久,和大家分享过如何把文本数据快速导入数据库(点击即可打开),今天再和大家分享一个小技能,将Oracle数据库中的数据按照指定分割符.指定字段导出至文本文件.首先来张图,看看导出的数据是什么 ...

  2. 数据仓库:Mysql大量数据快速导出

    背景 写这篇文章主要是介绍一下我做数据仓库ETL同步的过程中遇到的一些有意思的内容和提升程序运行效率的过程. 关系型数据库: 项目初期:游戏的运营数据比较轻量,相关的运营数据是通过Java后台程序聚合 ...

  3. AX 利用windows粘贴板功能实现批量数据快速导出EXCEL

    static void test(Args _args) { int lineNum; int titleLines; SysExcelApplication excel; SysExcelWorkb ...

  4. CRL快速开发框架系列教程十一(大数据分库分表解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  5. mysql远程快速导出csv格式数据工具

    如需转载,请经本人同意. 之前本人曾经写过一个使用 select ....into outfile原理导出数据的脚本,但该脚本值适用于本地快速导出,并不支持远程服务,故又编写了下面这个支持远程导出的脚 ...

  6. 使用HTML,CSS快速导出数据到Excel

    在应用中经常会遇到要从系统或数据库中导出数据平面文件,一般是导出到txt,csv或excel.txt和csv一般用在系统间的数据交换, 而excel一般有较好的显示效果,可以按照一定的模板导出,导出就 ...

  7. NPOI导出大量数据的避免OOM解决方案【SXSSFWorkbook】

    一.NPOI的基本知识 碰到了导出大量数据的需求场景:从数据读取数据大约50W,然后再前端导出给用户,整个过程希望能较快的完成.如果不能较快完成,可以给与友好的提示. 大量数据的导出耗时的主要地方: ...

  8. SQL SERVER 与ACCESS、EXCEL的数据导入导出转换

    * 说明:复制表(只复制结构,源表名:a 新表名:b)      select * into b from a where 1<>1 * 说明:拷贝表(拷贝数据,源表名:a 目标表名:b) ...

  9. SQL Server 2008空间数据应用系列十一:提取MapInfo地图数据中的空间数据解决方案

    原文:SQL Server 2008空间数据应用系列十一:提取MapInfo地图数据中的空间数据解决方案 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Serv ...

随机推荐

  1. 2016/12/30_Python

    今天主要学习内容: Python: 1.字典的使用 1)怎么创建字典 dicts = {"name":"juncx","age":17} d ...

  2. jQuery标准的AJAX模板

    $('#saveInformationTemplate_button').on('click', function(){ if(isEmpty($("#name").val())) ...

  3. Atitit 管理原理与实践attilax总结

    Atitit 管理原理与实践attilax总结 1. 管理学分类1 2. 我要学的管理学科2 3. 管理学原理2 4. 管理心理学2 5. 现代管理理论与方法2 6. <领导科学与艺术4 7. ...

  4. Atitit.你这些项目不都是模板吗?不是原创  集成和整合的方式大总结

    Atitit.你这些项目不都是模板吗?不是原创  集成和整合的方式大总结 1.1. 乔布斯的名言:创新即整合(Creativity is just connecting things).1 1.2. ...

  5. OpenGL ES: Array Texture初体验

    [TOC] Array Texture这个东西的意思是,一个纹理对象,可以存储不止一张图片信息,就是说是是一个数组,每个元素都是一张图片.这样免了频繁地去切换当前需要bind的纹理,而且可以节省系统资 ...

  6. Github使(zhuang)用(bi)指南

    本文针对未能熟练使用GitHub的人员,旨在为其指明通往新世界的小路. 一些闲话可以无视 在这个开源的时代,可能你听说过GitHub,知道大概是个什么.但是,你要是不能熟练的玩起来,怎么和大神取经,怎 ...

  7. 带你一分钟理解闭包--js面向对象编程

    上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...

  8. With(ReadPast)就不会被阻塞吗?

    在生产环境中,会有很多使用ReadPast查询提示的场合,来避免正在被其它事务锁定的行对当前查询造成阻塞,而又不会获取到“脏数据”. 可是很多人都疑惑,为什么我使用了ReadPast仍然有时会被阻塞? ...

  9. Windows 2008 - 由于管理员设置的策略,该磁盘处于脱机状态

    http://blog.sina.com.cn/s/blog_59cc90640102x8m4.html 查看原文:https://www.bxl.me/9279.html准备使用云主机挂机的时候呢出 ...

  10. iOS-----正则表达式的基础语法

    正则表达式简单语法总结 一.什么是正则表达式 从概念上来说,正则表达式也是一门小巧而精炼的语言,它可以用来简化检索特定的字符串,替换特定字符等功能,有许多开发语言工具,都内嵌支持正则表达式.那么一个正 ...