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);
}
При возврате необязательного
экземпляра это полезный намек на то, что значение может не существовать. Более подробную информацию о Факультативе можно найти здесь .
Все, что нам теперь нужно сделать, это указать тип возвращаемого значения как необязательный
:
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findOneByName(String name);
}
3. Потоковое
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 теперь мы можем определить, что наш метод репозитория возвращает только поток
объектов :
public interface UserRepository extends JpaRepository<User, Integer> {
// ...
Stream<User> findAllByName(String name);
// ...
}
Spring Data использует специфичную для провайдера реализацию для потоковой передачи результата (Hibernate использует ScrollableResultSet
, EclipseLink использует ScrollableCursor
). Это уменьшает объем потребления памяти и запросов к базе данных. Из-за этого это также намного быстрее, чем два решения, упомянутые ранее.
Обработка данных с помощью Stream
требует от нас закрытия Stream
, когда мы его закончим .
Это можно сделать, вызвав метод close()
для Stream
или используя try-with-resources
:
try (Stream<User> foundUsersStream
= userRepository.findAllByName(USER_NAME_ADAM)) {
assertThat(foundUsersStream.count(), equalTo(3l));
Мы также должны помнить о вызове метода репозитория внутри транзакции . В противном случае мы получим исключение:
org.springframework.dao.InvalidDataAccessApiUsageException
: вы пытаетесь выполнить метод потокового запроса без окружающей транзакции, которая поддерживает соединение открытым, чтобыпоток
мог фактически использоваться. Убедитесь, что код, потребляющий поток, использует@Transactional
или любой другой способ объявления транзакции (только для чтения).
4. Завершаемое будущее
Репозитории Spring Data могут работать асинхронно с поддержкой CompletableFuture
Java 8 и механизма Spring для асинхронного выполнения методов:
@Async
CompletableFuture<User> findOneByStatus(Integer status);
Клиент, который вызывает этот метод, немедленно вернет будущее, но метод продолжит выполнение в другом потоке.
Подробнее об обработке CompletableFuture
можно узнать здесь .
5. Вывод
В этом руководстве мы показали, как функции Java 8 работают вместе с Spring Data.
Полная реализация примеров доступна на Github .