流式传输查询

以下 findEachfindIteratefindStream 都是流式传输查询,主要区别在于使用闭包、迭代器或流的样式。通过这些流式传输查询,我们可以处理非常大的结果,而无需将所有结果保存在内存中。findEach 是推荐的样式,因为它确保查询持有的所有资源都已关闭,而无需使用带有资源块的 try。使用 findStreamfindIterate 同样不错,需要注意的是,我们需要确保 QueryIterator 和 Stream 通常通过 try with resources 关闭。

从 Ebean 12.3.5 版开始,这些流式传输查询使用“自适应持久化上下文”。这意味着 findEachfindIteratefindStream 对小型查询结果的处理效果与 findList 一样好。在处理了 1000 个 bean 之后,查询会调整它们使用的持久化上下文,以确保它不包含所有 bean(并且在处理非常大的结果时不会耗尽内存)。

处理少于 1000 个 bean 的查询使用单个普通持久化上下文。在处理了 1000 个 bean 之后,持久化上下文会进行调整,以便它不包含所有 bean。

findEach

执行查询,每次处理一个 bean 来处理结果。

new QCustomer()
 .status.equalTo(Status.NEW)
 .order().id.asc()
 .findEach((Customer customer) -> {

   // do something with customer
   System.out.println("-- visit " + customer);
 });

findEachWhile

findEach 类似,但采用一个谓词,允许我们尽早停止处理结果。

// Returning false inside the predicate will stop the execution
new QCustomer()
   .status.equalTo(Status.NEW)
   .order().id.asc()
   .findEachWhile((Customer customer) -> {
     // do something with customer
     ...
     // return true to continue processing or false to stop
     return (customer.getId() < 40);
   });

带有批处理消费者的 findEach

类似于 findEach,但将 bean 分批,以便可以分批处理它们 - 例如,每次处理 100 个批次。

new QCustomer()
 .status.equalTo(Status.NEW)
 .order().id.asc()
 .findEach(100, batch -> {
   // process the customers in batches of 100 at a time
   // where batch is List<Customer>
   ...
 });

findStream

执行查询,将结果作为流进行处理。使用 try with resources 块以确保流持有的资源已关闭。

try (Stream<Customer> stream =
  new QCustomer()
   .status.equalTo(Status.NEW)
   .order().id.asc()
   .findStream()) {

  stream
    .filter(...)
    .map(..)
    .collect(...);
}

findIterate

执行查询,将结果作为 QueryIterator 处理。使用 try with resources 块以确保迭代器持有的资源已关闭。

try (QueryIterator<Customer> it =
  new QCustomer()
   .status.equalTo(Status.NEW)
   .order().id.asc()
   .findIterate()) {

   while (it.hasNext()) {
     Customer customer = it.next();
     ...
   }
}