我试图预先生成一个非常大的表(300GB)在PostgreSQL的报告。 我做这样的事情:
rs = stmt.executeQuery("SELECT * FROM tbl");
System.out.println("select all finished");
while (rs.next()) {
/* generate report and save it in report table */
/* generated reports are not in memory,
* They are saved in a summary table in each iteration */
}
当我启动应用程序它给Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
。 我试图用stmt.setFetchSize(1000)
但它并没有解决问题。
解决办法是什么? 我使用Debian的6.0.5和OpenJDK的6 PostgreSQL的8.4.11。
[UPDATE]
打印的纸叠跟踪显示OutOfMemoryError
异常已被生成rs = stmt.executeQuery("SELECT * FROM tbl");
线。 另外System.out.println("select all finished");
从来没有显示。
- 我在运行的
autocommit
模式。 -
stmt.getResultSetConcurrency()
返回1007。 -
stmt.getResultSetHoldability()
返回2。 -
rs.getType()
返回1003。
这个问题可能是PostgreSQL只使用fetchSize
在狭窄的一些情况。 请参阅: http://jdbc.postgresql.org/documentation/91/query.html#fetchsize-example
- 到服务器的连接必须是使用V3协议。 这是默认的(并且只受支持)服务器版本7.4及更高版本。
- 该连接不能在自动提交模式。 后端在交易结束时关闭游标,所以在自动提交模式,后端将已关闭任何东西之前光标可以从中获取。
- 该语句必须以ResultSet类型ResultSet.TYPE_FORWARD_ONLY的创建。 这是默认的,所以没有代码需要重写,以利用这一优势,但它也意味着你不能向后滚动或以其他方式ResultSet中跳来跳去。
- 给出的查询必须是单个语句,用分号串成不是多个语句。
所以,如果你在执行此自动提交,或比其他结果集类型TYPE_FORWARD_ONLY
PostgreSQL将获取所有行。 也正看着PostgreSQL的JDBC驱动程序9.0-801它看起来像使用可保持结果集也将使其获取所有行的来源。
我不认为你有什么存在会导致那种错误的。 我相信,垃圾收集器,通过一起为您的迭代来rs.next()
所以你不应该有内存问题。 它可能有事情做与你试图对结果集做什么。 不知道你在做什么,虽然,我只能猜测你想要的一切存储在内存中的对象。 所以,如果你将值存储到一个StringBuilder
或东西,将是一个问题。 我建议把结果写入磁盘,当您去,而不是试图收集所有到内存中的对象(再次,我只是猜测你在做什么,因为你没有提供这方面的信息)。 在Java助手图书馆 ,有一个resultSetToCSVFile(ResultSet rs, String destination)
方法,你可能会发现有用的。 处理这种方式阻止你拿着它都在内存中,但你可以写你想的报告。 顺便说,要做到这一点,你需要包括opencsv库 。 或者你可以只通过包括直接调用该方法的Java助手库 。
/**
* Prints the given ResultSet to a comma separated file (the destination)
*
* @param rs
* @param destination
* @throws SQLException
* @throws FileNotFoundException
*/
public static void resultSetToCSVFile(ResultSet rs, String destination) throws SQLException, FileNotFoundException, IOException {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
String[] header = new String[columnCount];
for (int i = 0; i < columnCount; i++) {
header[i] = metaData.getColumnName(i + 1);
}
File file = new File(destination);
IOHelper.checkDirectory(file);
try (PrintWriter pw = new PrintWriter(file); CSVWriter writer = new CSVWriter(pw)) {
writer.writeNext(header);
while (rs.next()) {
String[] row = new String[columnCount];
for (int i = 0; i < columnCount; i++) {
String string = rs.getString(i + 1);
if (string == null) {
string = "";
}
row[i] = string;
}
writer.writeNext(row);
}
}
}