Найти тему

Разбивка на страницы в режиме Hibernate

Оглавление

1. Общий обзор

Эта статья представляет собой краткое введение в разбивку на страницы в Hibernate. Мы рассмотрим стандартный HQL, а также API ScrollableResults и, наконец, разбивку на страницы с использованием критериев Hibernate.

2. Разбивка на страницы с помощью HQL и API setFirstResult, setMaxResults

Самый простой и распространенный способ разбивки на страницы в Hibernate - это использование HQL:

Session session = sessionFactory.openSession();
Query<Foo> query = session.createQuery("From Foo", Foo.class);
query.setFirstResult(0);
query.setMaxResults(10);
List<Foo> fooList = fooList = query.list();

В этом примере используется базовая сущность Foo, и он очень похож на реализацию JPA с использованием JQL – единственным отличием является язык запросов.

Если мы
включим ведение журнала в режиме гибернации, мы увидим, что выполняется следующий SQL:

Hibernate:
select
foo0_.id as id1_1_,
foo0_.name as name2_1_
from
Foo foo0_ limit ?

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

Решение для разбивки на страницы не является полным без знания общего количества объектов:

String countQ = "Select count (f.id) from Foo f";
Query<Long> countQuery = session.createQuery(countQ, Long.class);
Long countResults = countQuery.uniqueResult();

И, наконец, исходя из общего количества и заданного размера страницы, мы можем рассчитать последнюю страницу:

int pageSize = 10;
int lastPageNumber = (int) (Math.ceil(countResults / pageSize));

На этом этапе мы можем рассмотреть полный пример разбивки на страницы, где мы вычисляем последнюю страницу и затем извлекаем ее:

@Test
public void givenEntitiesExist_whenRetrievingLastPage_thenCorrectSize() {
int pageSize = 10;
String countQ = "Select count (f.id) from Foo f";
Query<Long> countQuery = session.createQuery(countQ, Long.class);
Long countResults = (Long) countQuery.uniqueResult();
int lastPageNumber = (int) (Math.ceil(countResults / pageSize));

Query<Foo> selectQuery = session.createQuery("From Foo", Foo.class);
selectQuery.setFirstResult((lastPageNumber - 1) * pageSize);
selectQuery.setMaxResults(pageSize);
List<Foo> lastPage = selectQuery.list();

assertThat(lastPage, hasSize(lessThan(pageSize + 1)));
}

3. Разбивка на страницы в режиме гибернации с использованием HQL и API ScrollableResults

Использование ScrollableResults для разбивки на страницы может сократить количество обращений к базе данных. Такой подход позволяет передавать результирующий набор по мере его прокрутки программой, что устраняет необходимость повторять запрос для заполнения каждой страницы:

String hql = "FROM Foo f order by f.name";
Query query = session.createQuery(hql);
int pageSize = 10;

ScrollableResults resultScroll = query.scroll(ScrollMode.FORWARD_ONLY);
resultScroll.first();
resultScroll.scroll(0);
List<Foo> fooPage = Lists.newArrayList();
int i = 0;
while (pageSize > i++) {
fooPage.add((Foo) resultScroll.get(0));
if (!resultScroll.next())
break;
}

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

resultScroll.last();
int totalResults = resultScroll.getRowNumber() + 1;

С другой стороны, имейте в виду, что, хотя прокрутка достаточно эффективна, большое окно может занимать приличный объем памяти.

4. Разбивка на страницы в Hibernate с использованием API критериев

Наконец, давайте рассмотрим более гибкое решение – использование критериев:

CriteriaQuery<Foo> selectQuery = session.getCriteriaBuilder().createQuery(Foo.class);
selectQuery.from(Foo.class);
SelectionQuery<Foo> query = session.createQuery(selectQuery);
query.setFirstResult(0);
query.setMaxResults(pageSize);
List<Foo> firstPage = query.list();

API запроса критериев гибернации также позволяет очень просто получить общее количество:

HibernateCriteriaBuilder qb = session.getCriteriaBuilder();
CriteriaQuery<Long> cq = qb.createQuery(Long.class);
cq.select(qb.count(cq.from(Foo.class)));
final Long count = session.createQuery(cq).getSingleResult();

Как вы можете видеть, использование этого API приведет к получению как минимум более подробного кода, чем обычный HQL, но API полностью типизирован и намного более гибкий.

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

Эта статья представляет собой краткое введение в различные способы разбивки на страницы в Hibernate.

Оригинал статьи: https://www.baeldung.com/hibernate-pagination