我,谢谢你的关注。
我想用Java将大量数据,实际上是大量数据(600万行)导出到一个.csv文件。这个应用程序是一个swing应用程序,带有jpa,使用toplink(ojdbc14)。
我试图使用:
缓冲写入程序
随机存取文件
文件通道
ETC等,但是内存消耗仍然很高,导致Java堆内存不足,虽然我在800米(-xMx800 m)中设置了最大堆大小。
我最后一个版本的灵魂密码:
...(more lines of code)
FileChannel channel = getRandomAccessFile(tempFile).getChannel();
Object[][] data = pag.getRawData(); //Database data in a multidimentional array
for (int j = 0; j < data.length; j++) {
write(data[j], channel); //write data[j] (an array) into the channel
freeStringLine(data[j]); //data[j] is an array, this method sets all positions =null
data[j] = null;//sets reference in null
}
channel.force(false); //force writing in file system (HD)
channel.close(); //Close the channel
pag = null;
...(more lines of code)
private void write(Object[] row, FileChannel channel) throws DatabaseException {
if (byteBuff == null) {
byteBuff = ByteBuffer.allocateDirect(1024 * 1024);
}
for (int j = 0; j < row.length; j++) {
if (j < row.length - 1) {
if (row[j] != null) {
byteBuff.put(row[j].toString().getBytes());
}
byteBuff.put(SPLITER_BYTES);
} else {
if (row[j] != null) {
byteBuff.put(row[j].toString().getBytes());
}
}
}
byteBuff.put("\n".toString().getBytes());
byteBuff.flip();
try {
channel.write(byteBuff);
} catch (IOException ex) {
throw new DatabaseException("Imposible escribir en archivo temporal de exportación : " + ex.getMessage(), ex.getCause());
}
byteBuff.clear();
}
由于有600万行,我不想在创建文件时将数据存储在内存中。我创建了许多临时文件(每个文件有5000行),在最后一个过程中,使用两个文件通道将所有这些临时文件追加到一个文件中。但是,在加入之前会启动内存不足的异常。
你现在有没有另一个出口大量数据的策略?
非常感谢你的帮助。对不起,我的英语进步了
最佳答案
答案是使用“流”方法-即读取一行,在数据集中滚动时写入一行。您需要将查询结果作为游标获取并遍历它,而不是获取整个结果集。
在jpa中,使用如下代码:
ScrollableResults cursor = session.createQuery("from SomeEntity x").scroll();
while (cursor.next()) {
writeToFile(cursor);
}
这意味着您一次只能在内存中有一行,它完全可以扩展到任何行数,并且使用最少的内存(无论如何它更快)。
在一个结果集中同时获取所有行是一种方便的方法,它适用于小的结果集(大多数情况下都是这样),但是和往常一样,方便是要付出代价的,并且在所有情况下都不起作用。