Рубрики
Без рубрики

Пагинация в режиме гибернации

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

Автор оригинала: Eugen Paraschiv.

1. Обзор

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

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

Загрузка Hibernate 5 с пружиной

Отображение наследования в режиме гибернации

Показать инструкции Hibernate/JPA SQL из Spring Boot

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

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

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

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

Если мы включим ведение журнала для Hibernate , мы увидим, что выполняется следующий 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 countQuery = session.createQuery(countQ);
Long countResults = (Long) 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 countQuery = session.createQuery(countQ);
    Long countResults = (Long) countQuery.uniqueResult();
    int lastPageNumber = (int) (Math.ceil(countResults / pageSize));

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

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

3. Разбиение на страницы С помощью Hibernate С использованием HQL и API ScrollableResults

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

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 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 Критериев

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

Criteria criteria = session.createCriteria(Foo.class);
criteria.setFirstResult(0);
criteria.setMaxResults(pageSize);
List firstPage = criteria.list();

Hibernate Criteria query API позволяет очень просто также получить общее количество – с помощью проекции объекта:

Criteria criteriaCount = session.createCriteria(Foo.class);
criteriaCount.setProjection(Projections.rowCount());
Long count = (Long) criteriaCount.uniqueResult();

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

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

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

Реализацию этого весеннего руководства по JPA можно найти в проекте GitHub – это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.