Перейти к основному содержимому

CrudRepository, JpaRepository и PagingAndSortingRepository в данных Spring

· 5 мин. чтения

1. Обзор

В этой быстрой статье мы сосредоточимся на различных типах интерфейсов репозитория Spring Data и их функциональности. Мы коснемся:

  • CrudRepository
  • PagingAndSortingRepository
  • JpaРепозиторий

Проще говоря, каждый репозиторий в Spring Data расширяет общий интерфейс репозитория , но помимо этого каждый из них имеет разные функциональные возможности.

2. Хранилища данных Spring

Начнем с JpaRepository — который расширяет PagingAndSortingRepository и, в свою очередь, CrudRepository .

Каждый из них определяет свою собственную функциональность:

  • CrudRepository предоставляет функции CRUD
  • PagingAndSortingRepository предоставляет методы для разбиения на страницы и сортировки записей
  • 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 с определенными свойствами, и мы должны указать как минимум:

  1. Размер страницы
  2. Текущий номер страницы
  3. Сортировка

Итак, давайте предположим, что мы хотим отобразить первую страницу результирующего набора, отсортированную по 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

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

  1. мы связываем наш код с библиотекой и ее конкретными абстракциями, такими как Page или Pageable; это, конечно, не уникально для этой библиотеки, но мы должны быть осторожны, чтобы не раскрыть эти внутренние детали реализации.
  2. расширяя, например , CrudRepository , мы сразу предоставляем полный набор методов сохранения. Это, вероятно, хорошо в большинстве случаев, но мы можем столкнуться с ситуациями, когда мы хотели бы получить более детальный контроль над открытыми методами, например, создать ReadOnlyRepository , который не включает save(…) и delete( …) методы CrudRepository

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

В этой статье были рассмотрены некоторые краткие, но важные отличия и особенности интерфейсов репозитория Spring Data JPA.

Для получения дополнительной информации ознакомьтесь с серией статей о Spring Persistence .