JPA Pagination
1. обзор
В этой статье показано, как реализоватьpagination in the Java Persistence API.
В нем объясняется, как выполнять разбиение на страницы с помощью базового JQL и более безопасных типов API на основе критериев, обсуждаются преимущества и известные проблемы каждой реализации.
Дальнейшее чтение:
Нумерация страниц с помощью Spring REST и AngularJS таблицы
Подробно рассмотрим, как реализовать простой API с разбиением на страницы в Spring и как использовать его с AngularJS и UI Grid.
Spring JPA - несколько баз данных
Как настроить Spring Data JPA для работы с несколькими отдельными базами данных.
Spring Data JPA @Query
Узнайте, как использовать аннотацию @Query в Spring Data JPA для определения пользовательских запросов с использованием JPQL и собственного SQL.
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, поэтому его должно быть легко импортировать и запускать как есть.