Spring Data Java 8 Support – Spring Data Java 8支持

最后修改: 2018年 1月 2日

1. Overview


Spring Data now supports core Java 8 features – such as Optional, Stream API and CompletableFuture.

Spring Data现在支持Java 8的核心特性–如OptionalStream API和CompletableFuture

In this quick article, we’ll go through some examples of how we can use these with the framework.


2. Optional


Let’s start with the CRUD repository methods – which now wrap results in an Optional:


public interface CrudRepository<T, ID> extends Repository<T, ID> {
    Optional<T> findById(ID id);

When returning an Optional instance, it’s a useful hint that there’s a possibility that the value might not exist. More information on Optional can be found here.


All we now have to do is to specify return type as an Optional:


public interface UserRepository extends JpaRepository<User, Integer> {
    Optional<User> findOneByName(String name);

3. Stream API

3.Stream API

Spring Data also provides the support for one of the most important features of Java 8 – the Stream API.

Spring Data还提供了对Java 8最重要特性之一的支持–Stream API。

In the past, whenever we needed to return more than one result, we needed to return a collection:


public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    List<User> findAll();
    // ...

One of the problems with this implementation was the memory consumption.


We had to eagerly load and keep all retrieved objects in it.


We could improve by leveraging paging:


public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    Page<User> findAll(Pageable pageable);
    // ...

In some scenarios, that’s enough, but in others – pagination is really not the way to go, due to the high number of requests necessary to retrieve the data.


Thanks to Java 8 Stream API and JPA providers – we can now define that our repository method returns just a Stream of objects:

感谢Java 8 Stream API和JPA提供者–我们现在可以定义我们的存储库方法只返回一个Stream对象

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    Stream<User> findAllByName(String name);
    // ...

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.

Spring Data使用特定提供者的实现来流化结果(Hibernate使用ScrollableResultSet,EclipseLink使用ScrollableCursor)。它减少了内存消耗和对数据库的查询调用。正因为如此,它也比前面提到的两种解决方案快得多。

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:


try (Stream<User> foundUsersStream 
  = userRepository.findAllByName(USER_NAME_ADAM)) {
assertThat(foundUsersStream.count(), equalTo(3l));

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:

在Java 8的CompletableFuture和Spring异步方法执行机制的支持下,Spring Data存储库可以异步运行。

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.


More info about CompletableFuture processing can be found here.


5. Conclusion


In this tutorial, we showed how Java 8 features work together with Spring Data.

在本教程中,我们展示了Java 8的特性如何与Spring Data一起工作。

The full implementation of the examples is available over on Github.