我正在尝试将大型ResulSet(~1mm行)写入单个文件。在Java 1.6中是否有一种首选/有效的方法?
答案 0 :(得分:13)
这取决于使用的JDBC驱动程序。您需要指示JDBC驱动程序不事先将整个ResultSet
加载到Java的内存中,而是在每次next()
调用时按行加载它。然后,在ResultSet#next()
循环内,您需要将数据立即写入文件,而不是将其保存在List
或其他内容中。
目前还不清楚你正在使用什么JDBC驱动程序,但是例如可以指示MySQL JDBC驱动程序按照以下MySQL JDBC driver documentation的方式按行进行结果集:
结果集
默认情况下,ResultSet完全检索并存储在内存中。在大多数情况下,这是最有效的操作方式,并且由于MySQL网络协议的设计更容易实现。如果您正在使用具有大量行或大值的ResultSet,并且无法在JVM中为所需内存分配堆空间,则可以告诉驱动程序一次将结果流回一行。
要启用此功能,您需要以下列方式创建Statement实例:
stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE);
这是一个具体的启动示例:
try (
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("/records.txt")), "UTF-8"));
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
) {
statement.setFetchSize(Integer.MIN_VALUE);
try (ResultSet resultSet = statement.executeQuery("SELECT col1, col2, col3 FROM sometable")) {
while (resultSet.next()) {
writer.append(resultSet.getString("col1")).append(",")
.append(resultSet.getString("col2")).append(",")
.append(resultSet.getString("col3")).println();
}
}
}
顺便说一句,我首先检查数据库是否没有内置的SQL支持,这可以更有效地做到这一点。例如,MySQL为此提供了SELECT INTO OUTFILE
construct。
SELECT ... INTO OUTFILE 'file_name'
形式SELECT
将所选行写入文件。该文件是在服务器主机上创建的,因此您必须具有FILE
权限才能使用此语法。 file_name不能是现有文件,除其他外,它会阻止诸如/etc/passwd
和数据库表之类的文件被销毁。从MySQL 5.1.6开始,character_set_filesystem
系统变量控制文件名的解释。
答案 1 :(得分:0)
public static void writeResultSetToWriter(ResultSet resultSet, PrintWriter writer) throws SQLException
{
ResultSetMetaData metadata = resultSet.getMetaData();
int numColumns = metadata.getColumnCount();
int numRows = 0;
while(resultSet.next()) //iterate rows
{
++numRows;
JSONObject obj = new JSONObject(); //extends HashMap
for (int i = 1; i <= numColumns; ++i) //iterate columns
{
String column_name = metadata.getColumnName(i);
obj.put(column_name, resultSet.getObject(column_name));
}
writer.println(obj.toJSONString());
if(numRows % 1000 == 0)
writer.flush();
}