Автор оригинала: Eugen Paraschiv.
1. Обзор
В этой статье показано, как реализовать разбиение на страницы в Java Persistence API .
В нем объясняется, как выполнять подкачку с помощью базового JQL и более типобезопасных API на основе критериев, обсуждая преимущества и известные проблемы каждой реализации.
Дальнейшее чтение:
Разбиение на страницы с весенним отдыхом и таблицей AngularJS
Spring JPA – Несколько баз данных
Spring Data JPA @Query
2. Разбиение на страницы С помощью JQL и API setFirstResult(), setMaxResults()
Самый простой способ реализовать разбиение на страницы – использовать язык запросов Java – создать запрос и настроить его с помощью setMaxResults | и s e tFirstResult :
Query query = entityManager.createQuery("From Foo"); int pageNumber = 1; int pageSize = 10; query.setFirstResult((pageNumber-1) * pageSize); query.setMaxResults(pageSize); ListfooList = query.getResultList();
API прост:
- setFirstResult(int ) : Устанавливает положение смещения в результирующем наборе для начала разбиения на страницы
- setMaxResults(int) : Задает максимальное количество объектов, которые должны быть включены на страницу
2.1. Общее количество и Последняя страница
Для более полного решения по разбиению на страницы нам также нужно будет получить общее количество результатов :
Query queryTotal = entityManager.createQuery ("Select count(f.id) from Foo f"); long countResult = (long)queryTotal.getSingleResult();
Вычисление последней страницы также очень полезно:
int pageSize = 10; int pageNumber = (int) ((countResult / pageSize) + 1);
Обратите внимание, что этот подход к получению общего количества результирующего набора требует дополнительного запроса (для количества).
3. Разбиение на страницы С помощью JQL С использованием идентификаторов сущностей
Простая альтернативная стратегия разбиения на страницы состоит в том, чтобы сначала получить полные идентификаторы , а затем – на их основе – получить полные сущности . Это позволяет лучше контролировать выборку сущностей, но это также означает, что для получения идентификаторов необходимо загрузить всю таблицу:
Query queryForIds = entityManager.createQuery( "Select f.id from Foo f order by f.lastName"); ListfooIds = 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 С Использованием API Критериев
Далее давайте рассмотрим, как мы можем использовать API критериев JPA для реализации разбиения на страницы:
int pageSize = 10; CriteriaBuilder criteriaBuilder = entityManager .getCriteriaBuilder(); CriteriaQuerycriteriaQuery = 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 уменьшают сбои во время выполнения, поскольку компилятор динамически проверяет наличие ошибок запроса.
С критериями JPA получение общего количества сущностей достаточно просто:
CriteriaQuerycountQuery = criteriaBuilder .createQuery(Long.class); countQuery.select(criteriaBuilder.count( countQuery.from(Foo.class))); Long count = entityManager.createQuery(countQuery) .getSingleResult();
Конечным результатом является полное решение для разбиения на страницы , использующее API критериев JPA:
int pageNumber = 1; int pageSize = 10; CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuerycountQuery = 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.
Некоторые из них имеют недостатки, в основном связанные с производительностью запросов, но они обычно компенсируются улучшенным контролем и общей гибкостью.
Реализацию этого весеннего руководства по JPA можно найти в проекте GitHub – это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.