mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-24 12:53:59 +00:00
#811 - ENH: Restore findIterate() as alternative to findEach / findEachWhile
This commit is contained in:
@@ -761,6 +761,25 @@ public interface EbeanServer {
|
||||
*/
|
||||
<A> List<A> findIds(Query<?> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a QueryIterator for the query.
|
||||
* <p>
|
||||
* Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or
|
||||
* {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred
|
||||
* to findIterate(). The reason is that those methods automatically take care of
|
||||
* closing the queryIterator (and the underlying jdbc statement and resultSet).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is similar to findEach in that not all the result beans need to be held
|
||||
* in memory at the same time and as such is good for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
* <p>
|
||||
|
||||
@@ -147,6 +147,13 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query process the beans one at a time.
|
||||
*
|
||||
|
||||
@@ -544,6 +544,46 @@ public interface Query<T> {
|
||||
*/
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results (typically in a finally block).
|
||||
* </p>
|
||||
* <p>
|
||||
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
|
||||
* the jdbc statement and resultSet are closed at the end of the iteration.
|
||||
* </p>
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time.
|
||||
* <p>
|
||||
@@ -552,6 +592,11 @@ public interface Query<T> {
|
||||
* (unlike #findList #findSet etc)
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findEach (and findEachWhile and findIterate) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that internally Ebean can inform the JDBC driver that it is expecting larger
|
||||
* resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
|
||||
* from buffering the entire resultSet. As such, for smaller resultSets findList() is
|
||||
@@ -588,6 +633,11 @@ public interface Query<T> {
|
||||
* Execute the query using callbacks to a visitor to process the resulting
|
||||
* beans one at a time.
|
||||
* <p>
|
||||
* Note that findEachWhile (and findEach and findIterate) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results (typically in a finally block).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
@@ -71,10 +71,8 @@ import javax.persistence.NonUniqueResultException;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -1304,6 +1302,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return new LimitOffsetPagedList<T>(this, spiQuery);
|
||||
}
|
||||
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIterate();
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.endTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
@@ -12,7 +13,6 @@ import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.HashQuery;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
@@ -358,6 +358,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.findIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return query.findIterate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
query.findEach(consumer);
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.avaje.ebean.PagedList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.search.Match;
|
||||
@@ -375,6 +376,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.findIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return exprList.findIterate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
exprList.findEach(consumer);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
@@ -10,7 +10,7 @@ import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.core.DiffHelp;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Str;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.sql.SQLException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryEngine;
|
||||
|
||||
@@ -1114,6 +1114,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
server.findEach(this, consumer, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return server.findIterate(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Version<T>> findVersions() {
|
||||
this.temporalMode = TemporalMode.VERSIONS;
|
||||
|
||||
@@ -470,6 +470,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction) {
|
||||
|
||||
|
||||
@@ -27,6 +27,32 @@ public class TestQueryFindIterate extends BaseTestCase {
|
||||
|
||||
EbeanServer server = Ebean.getServer(null);
|
||||
|
||||
Query<Customer> query = server.find(Customer.class)
|
||||
.setMaxRows(2);
|
||||
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
|
||||
QueryIterator<Customer> it = query.findIterate();
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
Customer customer = it.next();
|
||||
customer.getName();
|
||||
count.incrementAndGet();
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
|
||||
assertEquals(2, count.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEach() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
EbeanServer server = Ebean.getServer(null);
|
||||
|
||||
Query<Customer> query = server.find(Customer.class)
|
||||
.setAutoTune(false)
|
||||
//.fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id")
|
||||
|
||||
Reference in New Issue
Block a user