流式传输查询
以下 findEach、findIterate 和 findStream 都是流式传输查询,主要区别在于使用闭包、迭代器或流的样式。通过这些流式传输查询,我们可以处理非常大的结果,而无需将所有结果保存在内存中。findEach 是推荐的样式,因为它确保查询持有的所有资源都已关闭,而无需使用带有资源块的 try。使用 findStream 和 findIterate 同样不错,需要注意的是,我们需要确保 QueryIterator 和 Stream 通常通过 try with resources
关闭。
从 Ebean 12.3.5 版开始,这些流式传输查询使用“自适应持久化上下文”。这意味着 findEach、findIterate 和 findStream 对小型查询结果的处理效果与 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();
...
}
}