1. Обзор
В этой быстрой статье мы сосредоточимся на различных типах интерфейсов репозитория Spring Data и их функциональности. Мы коснемся:
CrudRepository
PagingAndSortingRepository
JpaРепозиторий
Проще говоря, каждый репозиторий в Spring Data расширяет общий интерфейс репозитория
, но помимо этого каждый из них имеет разные функциональные возможности.
2. Хранилища данных Spring
Начнем с JpaRepository
— который расширяет PagingAndSortingRepository
и, в свою очередь, CrudRepository
.
Каждый из них определяет свою собственную функциональность:
CrudRepository
предоставляет функции CRUDPagingAndSortingRepository
предоставляет методы для разбиения на страницы и сортировки записейJpaRepository
предоставляет методы, связанные с JPA, такие как очистка контекста сохранения и удаление записей в пакете.
Итак, из-за этого отношения наследования JpaRepository
содержит полный API CrudRepository
и PagingAndSortingRepository
.
Когда нам не нужна полная функциональность, предоставляемая JpaRepository
и PagingAndSortingRepository
, мы можем просто использовать CrudRepository
.
Давайте теперь рассмотрим быстрый пример, чтобы лучше понять эти API.
Мы начнем с простого объекта Product :
@Entity
public class Product {
@Id
private long id;
private String name;
// getters and setters
}
А давайте реализуем простую операцию — найдем Товар
по его названию:
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
Product findByName(String productName);
}
Это все. Репозиторий данных Spring автоматически сгенерирует реализацию на основе имени, которое мы ему предоставили.
Конечно, это был очень простой пример; вы можете углубиться в Spring Data JPA здесь .
3. CrudRepository
Давайте теперь посмотрим на код интерфейса CrudRepository
:
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
T findOne(ID primaryKey);
Iterable<T> findAll();
Long count();
void delete(T entity);
boolean exists(ID primaryKey);
}
Обратите внимание на типичную функциональность CRUD:
save(…) – сохранить
объектIterable
. Здесь мы можем передать несколько объектов, чтобы сохранить их в пакете.findOne(…)
— получить один объект на основе переданного значения первичного ключаfindAll ()
— получитьIterable
всех доступных объектов в базе данныхcount() —
возвращает общее количество сущностей в таблице.delete(…)
— удалить сущность на основе переданного объекта- exists(…) - проверить, существует ли объект на основе переданного значения первичного ключа
Этот интерфейс выглядит довольно общим и простым, но на самом деле он предоставляет все основные абстракции запросов, необходимые в приложении.
4. Репозиторий пейджинга и сортировки
Теперь давайте посмотрим на другой интерфейс репозитория, который расширяет CrudRepository
:
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
Этот интерфейс предоставляет метод findAll(Pageable pageable)
, который является ключом к реализации нумерации страниц.
При использовании Pageable
мы создаем объект Pageable
с определенными свойствами, и мы должны указать как минимум:
- Размер страницы
- Текущий номер страницы
- Сортировка
Итак, давайте предположим, что мы хотим отобразить первую страницу результирующего набора, отсортированную по lastName,
по возрастанию, имеющую не более пяти записей на каждой. Вот как мы можем добиться этого, используя определение PageRequest
и Sort
:
Sort sort = new Sort(new Sort.Order(Direction.ASC, "lastName"));
Pageable pageable = new PageRequest(0, 5, sort);
Передача выгружаемого объекта в запрос данных Spring вернет рассматриваемые результаты (первый параметр PageRequest отсчитывается
от нуля).
5. JpaРепозиторий
Наконец, мы взглянем на интерфейс JpaRepository
:
public interface JpaRepository<T, ID extends Serializable> extends
PagingAndSortingRepository<T, ID> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> save(Iterable<? extends T> entities);
void flush();
T saveAndFlush(T entity);
void deleteInBatch(Iterable<T> entities);
}
Опять же, давайте кратко рассмотрим каждый из этих методов:
findAll ()
— получитьсписок
всех доступных объектов в базе данныхfindAll(…)
– получитьсписок
всех доступных сущностей и отсортировать их по заданному условию.save(…) – сохранить
объектIterable
. Здесь мы можем передать несколько объектов, чтобы сохранить их в пакете.flush() —
сбросить все отложенные задачи в базу данныхsaveAndFlush(…)
— сохранить сущность и немедленно сбросить изменения- deleteInBatch(…) — удалить
Iterable
сущностей. Здесь мы можем передать несколько объектов, чтобы удалить их в пакетном режиме.
Очевидно, что приведенный выше интерфейс расширяет PagingAndSortingRepository
, что означает, что он также имеет все методы, присутствующие в CrudRepository
.
6. Недостатки репозиториев данных Spring
Помимо всех очень полезных преимуществ этих репозиториев, есть и некоторые основные недостатки прямой зависимости от них:
- мы связываем наш код с библиотекой и ее конкретными абстракциями, такими как
Page
илиPageable
; это, конечно, не уникально для этой библиотеки, но мы должны быть осторожны, чтобы не раскрыть эти внутренние детали реализации. - расширяя, например ,
CrudRepository
, мы сразу предоставляем полный набор методов сохранения. Это, вероятно, хорошо в большинстве случаев, но мы можем столкнуться с ситуациями, когда мы хотели бы получить более детальный контроль над открытыми методами, например, создатьReadOnlyRepository
, который не включаетsave(…)
иdelete( …)
методыCrudRepository
7. Заключение
В этой статье были рассмотрены некоторые краткие, но важные отличия и особенности интерфейсов репозитория Spring Data JPA.
Для получения дополнительной информации ознакомьтесь с серией статей о Spring Persistence .