«1. Обзор

Spring Data теперь поддерживает основные функции Java 8, такие как Optional, Stream API и CompletableFuture.

В этой быстрой статье мы рассмотрим несколько примеров того, как мы можем использовать их с фреймворком.

2. Необязательный

Начнем с методов репозитория CRUD, которые теперь оборачивают результаты в необязательный: может не существовать. Дополнительную информацию о факультативе можно найти здесь.

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

Теперь все, что нам нужно сделать, это указать тип возвращаемого значения как необязательный:

3. Stream API

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

Spring Data также обеспечивает поддержку одной из наиболее важных функций Java 8 — потоковый 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 — теперь мы можем определить, что наш метод репозитория возвращает только поток объектов:

Spring Data использует специфичную для поставщика реализацию для потоковой передачи результата (Hibernate использует ScrollableResultSet, EclipseLink использует ScrollableCursor). Это уменьшает объем потребления памяти и запросов к базе данных. Из-за этого это также намного быстрее, чем два решения, упомянутые ранее.

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

Обработка данных с помощью потока требует, чтобы мы закрыли поток, когда мы его закончим.

Это можно сделать, вызвав метод close() для Stream или используя try-with-resources:

Мы также должны помнить о вызове метода репозитория внутри транзакции. В противном случае мы получим исключение:

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

4. CompletableFuture

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.

Spring Репозитории данных могут работать асинхронно с поддержкой механизма Java 8 CompletableFuture и Spring для асинхронного выполнения методов:

Клиент, который вызывает это Метод немедленно вернет будущее, но метод продолжит выполнение в другом потоке.

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

Дополнительную информацию об обработке CompletableFuture можно найти здесь.

5. Заключение

В этом руководстве мы показали, как функции Java 8 работают вместе со Spring Data.

Полная реализация примеров доступна на Github.

«