1. Обзор
Эта статья является кратким введением в Pagination в Hibernate . Мы рассмотрим стандартный HQL, а также API ScrollableResults
и, наконец, разбиение на страницы с помощью критериев Hibernate.
2. Пагинация с помощью HQL и setFirstResult,
setMaxResults
API
Самый простой и распространенный способ разбивки на страницы в Hibernate — использование HQL :
Session session = sessionFactory.openSession();
Query query = sess.createQuery("From Foo");
query.setFirstResult(0);
query.setMaxResults(10);
List<Foo> 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<Foo> lastPage = selectQuery.list();
assertThat(lastPage, hasSize(lessThan(pageSize + 1)));
}
3. Разбиение на страницы с помощью Hibernate с использованием 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 с использованием Criteria API
Наконец, давайте рассмотрим более гибкое решение — с использованием критериев:
Criteria criteria = session.createCriteria(Foo.class);
criteria.setFirstResult(0);
criteria.setMaxResults(pageSize);
List<Foo> firstPage = criteria.list();
API запросов Hibernate Criteria позволяет очень просто получить общее количество — с помощью объекта Projection :
Criteria criteriaCount = session.createCriteria(Foo.class);
criteriaCount.setProjection(Projections.rowCount());
Long count = (Long) criteriaCount.uniqueResult();
Как видите, использование этого API приведет к минимально более подробному коду, чем простой HQL, но API полностью типобезопасен и гораздо более гибкий .
5. Вывод
Эта статья представляет собой краткое введение в различные способы разбивки на страницы в Hibernate.
Реализацию этого учебного пособия по Spring JPA можно найти в проекте GitHub — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.