【发布时间】:2017-11-18 17:25:39
【问题描述】:
我正在尝试将 DB 查询的 ResultSet 保存到 ArrayList 以用作写入文件的输入,但内存不足。我正在阅读的表中有大约 116k 行数据。我尝试在readDB() 方法中直接写入文件,它创建了一个大约3.3 MB 的CSV-文件。这是我的代码。
public class Main {
public static void main(String[] args) {
DBAccess dbAccess = new DBAccess();
}
}
读取数据库的类和方法。
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class DBAccess {
public List<String> readDB() {
String url = "jdbc:Cobol://Dev/Project Files/DatAndCpyFiles";
try (Connection con = DriverManager.getConnection(url, "", "");
Statement stmt = con.createStatement())
{
stmt.setFetchSize(10);
Class.forName("com.hxtt.sql.cobol.CobolDriver").newInstance();
String sql = "select * from PROFS";
ResultSet rs = stmt.executeQuery(sql);
List<String> result = new ArrayList<>();
ResultSetMetaData resultSetMetaData = rs.getMetaData();
int iNumCols = resultSetMetaData.getColumnCount();
for (int i = 1; i <= iNumCols; i++) {
result.add(resultSetMetaData.getColumnLabel(i) + ";");
}
String row;
while (rs.next()) {
for (int i = 1; i <= iNumCols; i++) {
row = rs.getString(i);
row = row == null ? " " : row.replaceAll("\u0086", "å");
row = row == null ? " " : row.replaceAll("\u008F", "Å");
row = row == null ? " " : row.replaceAll("\u0084", "ä");
row = row == null ? " " : row.replaceAll("\u008E", "Ä");
row = row == null ? " " : row.replaceAll("\u0094", "ö");
row = row == null ? " " : row.replaceAll("\u0099", "Ö");
row = row == null ? " " : row.replaceAll("\u0081", "ü");
row = row == null ? " " : row.replaceAll("\u009A", "Ü");
row = row == null ? " " : row.replaceAll("\u0082", "é");
row = row == null ? " " : row.replaceAll("\u0090", "É");
result.add(result + row.trim() + ";");
}
}
rs.close();
System.out.println("Returning result");
return result;
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
return null;
}
}
}
错误信息
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractCollection.toString(AbstractCollection.java:462)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at se.spedweb.DBAccess.readDB(DBAccess.java:56)
at se.spedweb.Main.main(Main.java:15)
我可以为此使用什么其他数据结构?我为此使用了错误的方法吗?我可以将 append 写入文件而不是 add 以在方法中列出,但我认为在单独的类中写入文件和读取数据库会更干净,也许这是错误的。
【问题讨论】:
-
考虑使用回调,将写入器传递给数据库读取器(并一次调用一行)。然后,您将实际的写入逻辑(序列化一行)与读取逻辑分开。
-
这里的问题是试图将整个结果集加载到内存中。
-
String sql = "select * from PROFS";如果值在底层PROFStable 中更多,这可能是错误的 -
@ElliottFrisch 我不熟悉回调。我快速浏览了谷歌,但我不知道如何在这里应用它。在这种情况下,回调大致是什么样的?