【问题标题】:Java8 Stream batch processing to avoid OutOfMemoryJava8 Stream批处理以避免OutOfMemory
【发布时间】:2019-11-19 16:36:11
【问题描述】:

我有类似的东西:

    List<Data> dataList = stepts.stream()
        .flatMap(step -> step.getPartialDataList().stream())
        .collect(Collectors.toList());

所以我将每个步骤中的多个列表组合成 dataList

我的问题是 dataList 可能会遇到 OutOfMemoryError。 关于如何批处理 dataList 并将批处理保存到数据库中的任何建议?

我最初的想法是:

    for (Step step : steps) {
        List<Data> partialDataList = step.getPartialDataList();

        if (dataList.size() + partialDataList.size() <= MAXIMUM_SIZE) {
            dataList.addAll(partialDataList);
        } else {
            saveIntoDb(dataList);
            dataList = new ArrayList<>();
        }
    }

PS:我知道有this 的帖子,但不同的是我可能无法将整个数据存储在内存中。

LE:getPartialDataList 方法更像 createPartialDataList()

【问题讨论】:

  • 在将批次保存到数据库之前,您是否对数据执行了任何其他操作?
  • 可能?你尝试过吗?
  • 与这个问题进一步相关的是,我们在这里为List&lt;Data&gt; 讨论的数据大小是多少? getPartialDataList 是如何实现的?它是否将光标停留在数据读取上?
  • @vphilipnyc 不,只是保存它
  • @Eugene,可能,是的。我正在尝试从产品环境中找出所有极端情况。

标签: java mysql hibernate java-8 java-stream


【解决方案1】:

如果您关心的是OutOfMemoryError,您可能不应该在保存到数据库之前创建额外的中间数据结构,例如列表或流。

由于Step.getPartialDataList() 已经返回List&lt;Data&gt;,因此数据已经在内存中,除非您有自己的List 实现。你只需要使用JDBC batch insert:

PreparedStatement ps = c.prepareStatement("INSERT INTO data VALUES (?, ?, ...)");
for (Step step : steps) {
    for (Data data : step.getPartialDataList()) {
        ps.setString(1, ...);
        ps.setString(2, ...);
        ...
        ps.addBatch();
    }   
}
ps.executeBatch();

没有必要使用dataList 过早地分块成更小的批次。在进行过早优化之前,请先查看您的数据库和 JDBC 驱动程序支持什么。

请注意,对于大多数数据库来说,插入大量数据的正确方法是外部实用程序,而不是 JDBC,例如PostgreSQL has COPY.

【讨论】:

  • 最好的情况是对所有数据进行批量插入。但在 prod 环境中,获得 OutOfMemory 的机会可能很小。在 step.getPartialDataList() 上我会动态创建数据,也许这里的命名不是最好的。但毫无疑问,整个数据不在内存中
  • @UnguruBulan 我认为这个答案仍然适合您的用例。您一次处理的数据不能少于一个getPartialDataList()的结果
  • 我想处理比getPartialDataList()的结果更多的数据
猜你喜欢
  • 1970-01-01
  • 2020-01-28
  • 2018-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
相关资源
最近更新 更多