JPA Нумерация страниц

JPA Pagination

1. обзор

В этой статье показано, как реализоватьpagination in the Java Persistence API.

В нем объясняется, как выполнять разбиение на страницы с помощью базового JQL и более безопасных типов API на основе критериев, обсуждаются преимущества и известные проблемы каждой реализации.

Дальнейшее чтение:

Нумерация страниц с помощью Spring REST и AngularJS таблицы

Подробно рассмотрим, как реализовать простой API с разбиением на страницы в Spring и как использовать его с AngularJS и UI Grid.

Read more

Spring JPA - несколько баз данных

Как настроить Spring Data JPA для работы с несколькими отдельными базами данных.

Read more

Spring Data JPA @Query

Узнайте, как использовать аннотацию @Query в Spring Data JPA для определения пользовательских запросов с использованием JPQL и собственного SQL.

Read more

2. Пагинация с помощью JQL и APIsetFirstResult(),setMaxResults()

Самый простой способ реализовать разбиение на страницы - использоватьthe Java Query Language - создать запрос и настроить его черезsetMaxResults ** иsetFirstResult:

Query query = entityManager.createQuery("From Foo");
int pageNumber = 1;
int pageSize = 10;
query.setFirstResult((pageNumber-1) * pageSize);
query.setMaxResults(pageSize);
List  fooList = query.getResultList();

API прост:

  • *setFirstResult(int*): Устанавливает позицию смещения в наборе результатов для начала разбивки на страницы

  • setMaxResults(int): устанавливает максимальное количество объектов, которые должны быть включены на страницу.

2.1. Общее количество и последняя страница

Для более полного решения разбивки на страницы нам также потребуется получитьthe total result count:

Query queryTotal = entityManager.createQuery
    ("Select count(f.id) from Foo f");
long countResult = (long)queryTotal.getSingleResult();

Вычислениеthe last page также очень полезно:

int pageSize = 10;
int pageNumber = (int) ((countResult / pageSize) + 1);

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

3. Пагинация с помощью JQL с использованием идентификаторов сущностей

Простая альтернативная стратегия разбивки на страницы - этоfirst retrieve the full ids, а затем - на основе этого -retrieve the full entities. Это позволяет лучше контролировать выборку объектов, но также означает, что для получения идентификаторов необходимо загрузить всю таблицу:

Query queryForIds = entityManager.createQuery(
  "Select f.id from Foo f order by f.lastName");
List fooIds = queryForIds.getResultList();
Query query = entityManager.createQuery(
  "Select f from Foo e where f.id in :ids");
query.setParameter("ids", fooIds.subList(0,10));
List fooList = query.getResultList();

Наконец, также обратите внимание, что для получения полных результатов требуются 2 разных запроса.

4. Пагинация с помощью JPA с использованием Criteria API

Затем давайте посмотрим, как мы можемleverage the JPA Criteria API реализовать разбиение на страницы:

int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager
  .getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder
  .createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
TypedQuery typedQuery = entityManager.createQuery(select);
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(pageSize);
List fooList = typedQuery.getResultList();

Это полезно, когда целью является создание динамических, отказоустойчивых запросов. В отличие от «жестко запрограммированных», «строковых» запросов JQL или HQL,JPA Criteria сокращает сбои во время выполнения, поскольку компилятор динамически проверяет наличие ошибок запроса.

С критериями JPAgetting the total number of entities достаточно просто:

CriteriaQuery countQuery = criteriaBuilder
  .createQuery(Long.class);
countQuery.select(criteriaBuilder.count(
  countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
  .getSingleResult();

Конечный результат -a full pagination solution, используя API критериев JPA:

int pageNumber = 1;
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

CriteriaQuery countQuery = criteriaBuilder
  .createQuery(Long.class);
countQuery.select(criteriaBuilder
  .count(countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
  .getSingleResult();

CriteriaQuery criteriaQuery = criteriaBuilder
  .createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);

TypedQuery typedQuery = entityManager.createQuery(select);
while (pageNumber < count.intValue()) {
    typedQuery.setFirstResult(pageNumber - 1);
    typedQuery.setMaxResults(pageSize);
    System.out.println("Current page: " + typedQuery.getResultList());
    pageNumber += pageSize;
}

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

В этой статье были рассмотрены основные параметры пагинации, доступные в JPA.

У некоторых есть недостатки - в основном связанные с производительностью запросов, но они обычно компенсируются улучшенным контролем и общей гибкостью.

Реализацию этого Spring JPA Tutorial можно найти вthe GitHub project - это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.