转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/53457953,建议读者阅读原文,确保获得完整的信息
1.背景
最近在应对一个数据查询导出模块,总体要求就是依据给定的SQL语句,输出其查询结果为csv或者xlsx文件。其中查询数据量可能会有大数据量,成百上千万都可能。
2.探讨
针对上述数据导出这个问题,提取出几个关键词:
- 1、SQL是由作业人员临时写的。
- 2、数据量大。
- 3、输出csv或xlsx文件。
针对这几个关键词,咱分别扩展下其含义:
第一个关键词:SQL是临时写的,这就意味着咱只是去执行这条语句,并不能对语句进行分页设计啥的,如果要重新分析SQL可能比较困难。这个时候比较贴近的场景就是“数据库查询客户端”,客户端只管执行SQL,至于执行得快慢等取决于语句及数据库性能等。
第二个关键词:数据量大,即查询的返回结果可能比较多,你如何处理返回结果,是将其先存到List列表还是直接在结果集里面就给输出到文件。这就需要考虑内存、机器性能问题,不要一条语句执行了,直接导致你的java程序死掉了,比如JVM内存溢出,CPU使用率蹭蹭的涨到99%,导致整个程序无响应。
第三个关键词:输出csv或xlsx文件,比如csv是利用成熟的三方库还是自己写(毕竟就是逗号分隔的文本),不同人可能有不同看法,但是我主张大家用现成的三方依赖包,比如javacsv\opencsv都是比较成熟的工具包。
其中,有关csv读写在文章《 利用JavaCSV API来读写csv文件》中有详细介绍。而有关xlsx读写需要的jar包则在前面的文章《 Java处理excel两种不同的方式》有过介绍。
3.实现
在实例“Java导出数据库查询结果”中,我选取的实现方法为直接在ResultSet结果集中将数据写入到文件,这么操作基于两点:
- 1、做分页困难,没法降低查询数据量。
- 2、大数据量内存稀缺,尽量减少重复数据存储。
3.1导出csv
使用的依赖库:
<!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv -->
<dependency>
<groupId>net.sourceforge.javacsv</groupId>
<artifactId>javacsv</artifactId>
<version>2.1</version>
</dependency>
截取部分代码片段
// 判断文件是否存在,存在则删除,然后创建新表格
File tmp = new File(filePath);
if (tmp.exists()){
if (tmp.delete()){
logger.info(filePath + Constant.DUPLICATE_FILE_DELETE);
}
}
// 创建CSV写对象
CsvWriter csvWriter = new CsvWriter(filePath,Constant.SEPARATOR, Charset.forName("GBK"));
// 数据查询开始
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
// 获取结果集表头
ResultSetMetaData md = resultSet.getMetaData();
int columnCount = md.getColumnCount();
logger.debug("返回结果字段个数:" + columnCount);
JSONArray columnName = new JSONArray();
for (int i = 1; i <= columnCount; i++) {
JSONObject object = new JSONObject();
object.put(KEY.COLUNM_NAME,md.getColumnName(i));
columnName.add(object);
}
// 获取表头数组
int columnSize = columnName.size();
String[] columnNameList = ListUtil.getListFromJSONArray(columnName);
csvWriter.writeRecord(columnNameList);
// 数据记录数
int i = 0;
/