【问题标题】:Retrieving Large Lists of Objects Using Java EE使用 Java EE 检索大型对象列表
【发布时间】:2011-06-04 06:35:08
【问题描述】:

是否有一种普遍接受的方式来使用 Java EE 返回大量对象?

例如,如果您有一个包含数百万个对象的数据库 ResultSet,您将如何将这些对象返回给(远程)客户端应用程序?

另一个例子——更接近我实际所做的——是聚合来自数百个来源的数据,对其进行规范化,然后将其作为单个“列表”逐步传输到客户端系统。

由于所有数据都无法放入内存,因此我认为将有状态的 SessionBean 和某种回调到服务器的自定义迭代器组合起来就可以解决问题。

那么,换句话说,如果我有一个像 Iterator<Data> getData() 这样的 API,那么实现 getData()Iterator<Data> 的好方法是什么?

过去你是如何成功解决这个问题的?

【问题讨论】:

    标签: java jakarta-ee scalability


    【解决方案1】:

    绝对不要将整个数据库复制到 Java 的内存中。这是没有意义的,只会让事情变得不必要的缓慢和占用内存。而是在数据库级别引入分页。您应该只查询您实际上需要在当前页面上显示的数据,就像 Google 所做的那样。

    如果您确实很难正确实现这一点和/或为特定数据库计算 SQL 查询,请查看this answer。对于 JPA/Hibernate 等效项,请查看 this answer


    更新根据 cmets(实际上改变了整个问题主题...),这是一个基本(伪)启动示例:

    List<Source> inputSources = createItSomehow();
    Source outputSource = createItSomehow();
    
    for (Source inputSource : inputSources) {
        while (inputSource.next()) {
            outputSource.write(inputSource.read());
        }
    }
    

    通过这种方式,您可以有效地在 Java 内存中得到一个条目,而不是整个集合,如下面(低效)示例:

    List<Source> inputSources = createItSomehow();
    List<Entry> entries = new ArrayList<Entry>();
    
    for (Source inputSource : inputSources) {
        while (inputSource.next()) {
            entries.add(inputSource.read());
        }
    }
    
    Source outputSource = createItSomehow();
    
    for (Entry entry : entries) {
        outputSource.write(entry);
    }
    

    【讨论】:

    • 感谢您的回答。数据库只是一个例子。我没有使用数据库,也没有向用户显示信息。我基本上是从大量来源聚合数据并将其传输到另一个应用程序。
    • 然后我会在每个条目的基础上进行。立即处理/发送从输入到输出的单个条目,而不将完整的输入保存在 Java 的内存中。
    • 那么实现会是什么样子呢?我在想 API 将是“Iterator getData()”,但不确定实现 Iterator 的最佳方式。听起来您在谈论基于消息的解决方案?
    【解决方案2】:

    在使用基于 Web 的 UI 时,分页是一个很好的解决方案。但是,有时在一次通话中流式传输所有内容会更有效。 rmiio 库是为此目的明确编写的,并且已知可在各种应用服务器中工作。

    【讨论】:

    • 这看起来很有希望。我会仔细看看。谢谢。
    【解决方案3】:

    如果您的列表很大,您必须假设它无法放入内存。或者至少,如果您的服务器需要处理许多并发访问,那么您就有很高的 OutOfMemoryException 风险。

    所以基本上,你所做的就是分页和使用批量读取。假设您从数据库中加载 1000 个对象,然后将它们发送到客户端请求响应。然后循环直到处理完所有对象。 (参见 BalusC 的回复)

    客户端的问题是相同的,您可能需要将数据流式传输到文件系统以防止出现 OutOfMemory 错误。

    还请注意:从数据库加载数百万个对象作为管理任务是可以的:例如执行备份和导出一些“异常”情况。但是您不应该将其用作任何用户都可以执行的请求。这会很慢并且会消耗服务器资源。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-15
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 1970-01-01
      • 2014-12-09
      相关资源
      最近更新 更多