【发布时间】:2018-11-29 21:21:18
【问题描述】:
我正在对具有 16,213,156 行和 10 列的 MYSQL 表执行选择查询。但是在建立连接后,代码只执行了几分钟然后抛出错误:Exception in thread "Thread-3" java.lang.OutOfMemoryError: Java heap space
我的系统配置是 16 GB RAM,Java 8
我尝试将 Jvm 参数设置为 -Xms4G 和 -Xmx12G 。还尝试设置 stmt.setFetchSize(); // 到 10,100,1000 还是一样的错误
我们可以使用 JDBC API 获取如此大量的记录吗?我错过了什么吗?任何帮助将不胜感激。
package com;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import com.opencsv.CSVWriter;
public class Test1 {
private static Connection conn = null;
public static void main(String[] args) throws ClassNotFoundException, SQLException, IOException {
connection();
retrieve(conn);
}
public static void connection()
{
try
{
Class.forName("com.mysql.jdbc.Driver");
String url = "<jdbc connection url>";
conn = DriverManager.getConnection(url, "<username>", "<password>");
System.out.println("Connection established");
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void retrieve(Connection conn)
{
ResultSet rs = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
// stmt.setFetchSize(100); // 1000, 10
System.out.println(stmt.getFetchSize()); // By default prints 0
rs = stmt.executeQuery("SELECT * FROM tablename");
CSVWriter writer = new CSVWriter(new BufferedWriter(new FileWriter("C:\\finaldata\\test.csv")));
System.out.println("**** Started writing Data to CSV ****");
int lines = writer.writeAll(rs, true, false, false);
writer.flush();
writer.close();
System.out.println("** OpenCSV -Completed writing the resultSet at " + new Date() + " Number of lines written to the file " + lines);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
【问题讨论】:
-
为什么要在结果集中检索超过 100 万行?
-
为什么不分页?抓取记录 0-20、21-40、41-60 等...
-
你用分析器检查过什么消耗内存吗?使用 ResultSet 可以逐条提取数亿条记录
-
我同意@Ivan,您将不得不对此进行记忆分析。代码没有明显的问题。在内部,
writeAll()应用于ResultSet一次迭代一行。 -
单独设置获取大小可能不足以让 MySQL 驱动程序开始从数据库流式传输数据,而不是一次加载所有内容。你可以试试
stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE);(来自this answer)。