如何将sql查询附加到java中的现有文件?

时间:2019-06-14 10:07:21

标签: java bufferedwriter

我目前正在研究一个Java代码,该代码使我可以查询数据库并将其内容提取到文件中。

到目前为止,对于小请求没有问题。

但是我将很快不得不提取大量数据,并且我已经尝试了几天来实施最有效的解决方案,以便尽可能地限制内存消耗。

由于我提出了重要要求,因此源计算机和目标计算机的内存已饱和。

我在redhat linux环境上使用的Java版本是java-1.8.0

到目前为止,我已经能够将查询结果重定向到文件。但是经过大量的文档整理,我可以看到有很多不同的方法可以限制内存消耗。

DriverManager.registerDriver(new              
com.wily.introscope.jdbc.IntroscopeDriver());
Connection conn = DriverManager.getConnection("jdbc:introscope:net//" +     
user + ":" + password + "@" + hostname + ":" + port);       

String query = "select * from metric_data"
                + " where agent='"
                + agents_filter
                + "' and metric='"
                + metrics_filter
                + "' and timestamp between "
                + queryInterval;

Statement ps=conn.createStatement();
ResultSet rs=ps.executeQuery(query);

rs.setFetchSize(Size);
ResultSetMetaData rsm = rs.getMetaData();
File output = new File("result");
PrintWriter out = new PrintWriter(new BufferedWriter(
    new OutputStreamWriter(
    new FileOutputStream(output), "UTF-8")), false);

    for(int i = 1; i <= rs.getMetaData().getColumnCount(); i++){
    String colName = rs.getMetaData().getColumnName(i);
    out.print(" " + colName + "\t\t" + "|");
        }

        while (rs.next()) {
            for(int i = 1; i <= rs.getMetaData().getColumnCount(); i++){
                String colValue = rs.getString(i);
                out.print(" " + colValue + "\t" + "|");
                                                                        }

                out.println();
                        }


    out.close();
    out.flush();
    rs.close();
    ps.close();
    conn.close();

当前,请求已完全加载到内存中,然后重定向到我的文件。但是,一旦请求太重要,我就会收到以下消息:

线程“ PO:client_main Mailman 2”中的异常java.lang.OutOfMemoryError:Java堆空间 线程“ UnknownHub集线器接收1”中的异常java.lang.lang.OutOfMemoryError:Java堆空间

我希望能够在文件中写入1000乘1000的行,以免使内存饱和。

知道文件有时可以达到40gb

执行时间并不是真正的问题,但是内存消耗是一个非常重要的标准。

我远不是一名Java专业人士,所以这就是为什么我需要您的一些帮助。

提前感谢您的时间

1 个答案:

答案 0 :(得分:1)

  1. 通过串联字符串来构造SQL字符串是安全漏洞。想象一下,这些变量的内容类似于:"1'; DROP ALL TABLES; --"。即使在这里您知道字符串是“安全的”,代码也会更改,并且您不应该养成不良习惯。解决这个问题;您可以使用PreparedStatement对其进行修复。

  2. 元数据不是免费的。缓存这些东西。具体来说,请缓存值rs.getMetaData().getColumnCount()

  3. 要在此处获得实际速度,请运行一条SQL命令,该命令告诉DB引擎将数据直接泵送到文件中,如果该文件不在本地主机上,则将其传输。真的不能比这快。

  4. 关闭后无法刷新,关闭表示刷新。您只需删除flush()行。

  5. 假定您的提取大小不是可笑的大,那么此代码中没有任何内容指示发生内存不足错误。因此,要么是重复调用getMetaData(这意味着缓存列大小将在此处解决您的问题),要么是数据库引擎和/或其JDBC驱动程序的编写不正确。我没听说过内窥镜,这就是为什么我提到它。在这种情况下,充其量您可以使用SQL OFFSETLIMIT将查询分成“页面”,因此不会一次捕获太多结果,但是在其中没有ORDER您的SQL,从技术上讲,允许DB引擎更改您的顺序,使用它,过程可能会变得很慢。