Spring Data uses provider-specific implementation to stream the result (Hibernate uses ScrollableResultSet, EclipseLink uses ScrollableCursor). It reduces the amount of memory consumption and query calls to a database. Because of that, it’s also much faster than two solutions mentioned earlier.

Processing data with a Stream requires us to close a Stream when we finish it.

It can be done by calling the close() method on a Stream or by using try-with-resources:

We must also remember to call a repository method within a transaction. Otherwise, we’ll get an exception:

org.springframework.dao.InvalidDataAccessApiUsageException: You’re trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction.

4. CompletableFuture

Spring Data repositories can run asynchronously with the support of Java 8’s CompletableFuture and Spring mechanism for asynchronous method execution:

@Async
CompletableFuture<User> findOneByStatus(Integer status);

A client which calls this method will return a future immediately but a method will continue an execution in a different thread.