Spring Data Java 8 Support


1.概述

Spring Data现在支持核心Java 8功能 - 例如Optional,Stream API和CompletableFuture。

在这篇快速文章中,我们将通过一些示例来说明如何在框架中使用这些示例。

2. Optional

让我们从CRUD存储库方法开始 - 现在将结果包装在Optional中:

public interface CrudRepository<T, ID> extends Repository<T, ID> {

    Optional<T> findById(ID id);

}

返回Optional实例时,这是一个有用的提示,表明该值可能不存在。有关Optional的更多信息,请访问此处。

我们现在要做的就是将返回类型指定为Optional:

public interface UserRepository extends JpaRepository<User, Integer> {

    Optional<User> findOneByName(String name);

}

3. Stream API

Spring Data还支持Java 8最重要的功能之一 - Stream API。

过去,每当我们需要返回多个结果时,我们都需要返回一个集合:

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

这种实现的一个问题是内存消耗。

我们不得不急切地加载并保留所有检索到的对象。

我们可以通过利用分页来改进:

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

在某些情况下,这已经足够了,但在其他情况下 - 由于检索数据所需的大量请求,分页实际上不是可行的方法。

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

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

Spring Data使用特定于提供程序的实现来传输结果(Hibernate使用ScrollableResultSet,EclipseLink使用ScrollableCursor)。它减少了内存消耗量和查询对数据库的调用。因此,它也比前面提到的两个解决方案快得多。

使用Stream处理数据需要我们在完成后关闭Stream。

可以通过在Stream上调用close()方法或使用try-with-resources来完成:

try (Stream<User> foundUsersStream
  = userRepository.findAllByName(USER_NAME_ADAM)) {

assertThat(foundUsersStream.count(), equalTo(3l));

我们还必须记住在事务中调用存储库方法。否则,我们会得到一个例外:

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存储库可以与Java 8的CompletableFuture和Spring机制的支持异步运行,以实现异步方法:

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

调用此方法的客户端将立即返回未来,但方法将继续在不同的线程中执行。