java通过CSV文本格式来导出千万级大数据

Posted robot_sql

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java通过CSV文本格式来导出千万级大数据相关的知识,希望对你有一定的参考价值。

1、由于业务发展,当前页面导出只支持Excel导出数据时间过长已经不能满足系统需要,需要采用导出文本格式的方式来实现业务需求。

JAVA导出文本、mvn打包拒绝访问

NOT all named parameters have been set

java.lang.object无法转换成java.lang.string

2、java导出csv格式方法:

传入参数可以参照自己系统导出Excel的参数

response.setContentType("application/download;charset=UTF-8");
response.setContentType("Content-type:application/vnd.ms-excel;charset=UTF-8");
response.setHeader("Content-disposition","attachment;filename="+java.net.URLEncoder.encode(fileName, "UTF-8"));
outPutStream= response.getOutputStream();

List<HashMap<String,Object>> data = dpservice.getCSVDatalist(tableName, wheresql);

exportResultCSV(data,titleLine.split(","),colmLine.split(","),tableName,outPutStream);

    /**
     * 导出CSV数据方法
     * @param data         list集合
     * @param titleLine    表头字符串
     * @param colmLine     SQL列名,用于对应HashMap格式的key来获取值
     * @param tableName    表名
     * @param outPutStream 输出流
     * @throws IOException
     */
    public exportResultCSV(List<HashMap<String,Object>> data, String[] titleLine, String[] colmLine,String[] tableName, OutPutStream outPutStream) throws IOException
        StringBuffer expStr = new StringBuffer();
        try 
            //csv文件是逗号分隔,除第一个外,每次写入一个单元格数据后需要输入逗号
            for(String title : titleLine)
                expStr.append(title).append(",");
            
            //写完文件头后换行
            expStr.append("\\n");
            //写数据
            for(HashMap<String,Object> map : data)
                //for (String key : map.keySet()) 
                //String val = map.get(key) != null ? map.get(key).toString() : "";
                //expStr.append(val).append(",");
                
                //由于HashMap集合里面存储数据属于无序存储,上面的方法属于直接获取,会导致导出的列错位,如下写法规避
                for (int j=0,j<colmLine.length;j++) 
                    String val = map.get(colmLine[j].toUppercase()) != null ? map.get(colmLine[j].toUppercase()).toString() : ""; 
                    //'\\t'是为了导出格式为文本,避免长串数字变E+科学计数法
                    expStr.append(val).append("\\t").append(","); 
                
                //写完一行换行
                expStr.append("\\n");
                
        outPutStream.write(expStr.toString().getBytes("GBK"));
         catch (Exception e)
            e.printStackTrace();
        finally 
            // 关闭
            if(outPutStream != null)
                outPutStream.close();
            
        
    

由于上面的导出是放入的字符串,导致导出数据过大的时候会导致java内存溢出,java.lang.OutOfMemoryError :GC ....,所以需要对查询的数据进行分页导出,在mysql中拼接sql时多加个limit pagebeg,pageend的参数设置,内存溢出问题于是解决,新的问题是outPutStream= response.getOutputStream();方式直接浏览器下载只能生成同一个文件,也就是说你的sql结果集被你分成A1.csv,A2.csv,A3.csv,A4.csv时,导出来只有A1.csv,其他数据下载不下来了,由于response.getOutputStream()只响应一次页面,后续response的setHeader数据不会再改变了,不管你循环多少次都是第一份,所以需要将outPutStream= response.getOutputStream();改成outPutStream= new FileOutPutStream("下载路径+文件名+后缀");,这样就可以多份下载了,但是只能下载到你项目部署的服务器,项目部署动态路径如下获取this.getServletContext().getRealPath("/"),如此你就能下载到服务器了。

然后再从服务器通过浏览器将文件下载到到你的个人电脑,通过如下命令即可下载

IOUtils.copy(new FileInputStream("路径+文件名+后缀"),outPutStream) 这样就可以将原先的文件合成一个直接下载到本地了

import org.apache.commons.compress.utils.IOUtils; 用完后记得对IOUtils做close

3、java在拼接sql时,通过传入map参数来实现变量替换(传入方式=:),参数已经传入,直接报错NOT all named parameters have been set ,此错误是由于参数未被解析,需要通过如下代码先行转换:

/**
 * 解析替换具名参数
 * @param sql     要执行的SQL
 * @param paramap 参数map
 * @return        替换后的SQL
 */
public String findbySql(String sql, Map<String, object> paramap) 
 
        while (sql.indexOf(":") >= 0) 
            int x_liu = sql.indexOf(":");
            int y_liu = sql.substring(x_liu).indexOf(" ");
            int e_liu = sql.length();
            if (y_liu >= 0) 
                e_liu = x_liu + y_liu;
            
            String key_liu = sql.substring(x_liu + 1, e_liu);
            String value = (String)paramap.get(key_liu);  //需要转换下,object无法默认转成string
            if (null != value && !"null".equals(value)) 
                value = "'" + value + "'";
            
            sql = sql.substring(0, x_liu) + value + sql.substring(e_liu);
        
        return sql;
    

另外java.lang.object无法转换成java.lang.string的错误可以参照上面(String)paramap.get(key_liu)的写法。

4、mvn通过命令mvn clean package进行代码打包编译时出现/target/目录“拒绝访问”的错误,这时候需要重启电脑才能对此目录中的文件进行操作,具体原因为文件只有可读权限,需要增加文件夹所有用户(Everyone)所有的控制权限,增加文件加该用户权限自行百度(直接文件夹属性-》安全),不然经常需要重启电脑麻烦的一逼。

以上是关于java通过CSV文本格式来导出千万级大数据的主要内容,如果未能解决你的问题,请参考以下文章

java通过CSV文本格式来导出千万级大数据

JAVA Apache POI 之sax 解析10万级大数量数据

优化MySQL千万级大表优化解决方案

Mysql千万级大表优化

30个MySQL千万级大数据SQL查询优化技巧详解

30个mysql千万级大数据SQL查询优化技巧详解