Java-海量数据检索

Java-海量数据检索,java,performance,out-of-memory,Java,Performance,Out Of Memory,我有一个要求,在其中一个报告中,我需要从数据库中获取大约1000万条记录,并将它们传输到Excel 应用程序是客户机-服务器模型,其中服务器端逻辑用EJB编写,客户机用Swing编写 现在我的问题是,当我尝试从Resultset填充Java对象时,如果Resultset的大小大于(>100000),那么它会在Java端抛出内存不足错误 有人能告诉我这个场景应该如何用Java处理吗?我需要将所有记录从服务器传输到客户端,然后我需要根据从服务器端检索到的数据构建Excel报告。您可以使用-Xmx开关

我有一个要求,在其中一个报告中,我需要从数据库中获取大约1000万条记录,并将它们传输到Excel

应用程序是客户机-服务器模型,其中服务器端逻辑用EJB编写,客户机用Swing编写

现在我的问题是,当我尝试从Resultset填充Java对象时,如果Resultset的大小大于(>100000),那么它会在Java端抛出内存不足错误


有人能告诉我这个场景应该如何用Java处理吗?我需要将所有记录从服务器传输到客户端,然后我需要根据从服务器端检索到的数据构建Excel报告。

您可以使用-Xmx开关增加JVM可用的内存量(例如,-Xmx1024m将JVM设置为具有高达1GB的内存)


如果这不是一个选项,或者您已经这样做了,唯一的替代方法是重写服务器以分阶段返回结果,而不是一次返回所有结果。如何做到这一点将取决于服务器实现的具体情况。

您需要尽可能多地处理数据库端的数据。当你从数据库中读取数据时,或者至少在某种缓冲区中写入数据,这样你就不会在Java程序中加载所有数据。

我会使用LIMIT命令将结果集分成更小的块(mySQL,不知道这是否在其他数据库服务器中)。类似于以下伪代码:

long recsToget = 50000;
long got = recsToGet;
long offset = 0;
while ( got == recsToGet )
{
  got = getNextBatchFromDb( offset );
  writeBatchToCsv();
  offset += recsToGet; //increase your OFFSET each time
}
我会在getNextBatchFromDb()函数的SQL查询中使用LIMIT和OFFSET,如下所示:

select * from yourtable LIMIT 50000 OFFSET 100000
其中,偏移量是开始读取的位置,极限是要读取的数字


通过这样做,您可以以较小的块读取大数据集,并每次更新CSV,直到完成。当getNextBatchFromDb()返回比recsToGet小的行数时,您知道所有记录都已被读取。

您可以使用原语类型,而不是使用对象。注意:除非客户端的内存比服务器的内存多,否则将所有这些数据发送到客户端是没有意义的


通常,服务器会为客户端生成报告。这将最大限度地提高服务器所做的工作,并减少发送到客户端的数据。Excel不能处理工作表中超过一百万行的数据,其图表不能处理超过32000个点。我建议您在服务器上进行报告。

对于这种情况,对象不是好的选择。以下是处理此问题的几个选项

1) 从数据库检索记录并附加到报表时应用分页

2) 此选项取决于数据库服务器。一些DB服务器能够将任何查询的输出导出到平面文件。检查ur DB是否支持此功能。导出后,您可以从平面文件中读取内容并生成报告


很多朋友已经提到了excel的限制,所以你也要注意这一点。

excel在一张工作表中只能有一百万条记录。如果不是多个文档,我假设您使用的是多张工作表。根据我的经验,Excel的表现很差,记录远远少于1 mil。您确定您理解了这些需求吗?您所说的“不使用对象,您可以使用基本类型”是什么意思。如果我必须遵循您的建议,我应该如何返回数据?您似乎有一些问题,这表明您需要重新考虑您的方法。您可以使用原语数组来增加一次加载到Java内存中的数据量,但这只是您将遇到的问题之一(并且不会使excel问题消失)。关键问题是在excels限制内工作。您应该首先确定可以加载到excel中的最小值(以及excel是否可以加载这么多数据)。在你这么做之前,其余的都无关紧要。