Partner – JPA Buddy – NPI (tag=JPA/Hibernate)
announcement - icon

The right tools can and will save a lot of time. As long as you are using Hibernate and IntelliJ IDEA you can boost your coding speed and quality with JPA Buddy. It will help in a lot of the day-to-day work:

  • Creating JPA entities that follow best practices for efficient mapping
  • Creating DTOs from entities and MapStruct mappers using convenient visual tools
  • Generating entities from the existing database or Swagger-generated POJOs
  • Visually composing methods for Spring Data JPA repositories
  • Generating differential SQL to update your schema in accordance with your changes in entities
  • Autogenerating Flyway migrations and Liquibase changelogs comparing entities with the database or two databases
  • … and a lot more

Simply put, you'll learn and use the best practices of Hibernate and surrounding technology and become a lot more!

Definitely visit the JPA Buddy site to see its features in action closer.

Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE

1. Overview

This article is a quick introduction to Pagination in Hibernate. We will look at the standard HQL as well as the ScrollableResults API, and finally, at pagination with Hibernate Criteria.

Further reading:

Bootstrapping Hibernate 5 with Spring

A quick and practical guide to integrating Hibernate 5 with Spring.

Hibernate Inheritance Mapping

A practical guide to understanding different inheritance mapping strategies with JPA / Hibernate.

Show Hibernate/JPA SQL Statements from Spring Boot

Learn how you can configure logging of the generated SQL statements in your Spring Boot application.

2. Pagination With HQL and setFirstResult, setMaxResults API

The simplest and most common way to do pagination in Hibernate is using HQL:

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

This example is using a basic Foo entity and is very much similar to the JPA with JQL implementation – the only difference being the query language.

If we turn on logging for Hibernate, we'll see the following SQL being run:

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

2.1. The Total Count and the Last Page

A pagination solution is not complete without knowing the total number of entities:

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

And lastly, from the total number and a given page size, we can calculate the last page:

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

At this point we can look at a complete example for pagination, where we are calculating the last page and then retrieving it:

@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. Pagination With Hibernate Using HQL and the ScrollableResults API

Using ScrollableResults to implement pagination has the potential to reduce database calls. This approach streams the result set as the program scrolls through it, therefore eliminating the need to repeat the query to fill each page:

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;
}

This method is not only time-efficient (only one database call), but it allows the user to get access to the total count of the result set without an additional query:

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

On the other hand, keep in mind that, although scrolling is quite efficient, a large window may take up a decent amount of memory.

4. Pagination With Hibernate Using the Criteria API

Finally, let's look at a more flexible solution – using criteria:

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

Hibernate Criteria query API makes it very simple to also get the total count – by using a Projection object:

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

As you can see, using this API will result in minimally more verbose code than plain HQL, but the API is fully type safe and a lot more flexible.

5. Conclusion

This article is a quick introduction to the various ways of doing pagination in Hibernate.

The implementation of this Spring JPA Tutorial can be found in the GitHub project – this is an Eclipse based project, so it should be easy to import and run as it is.

Persistence bottom

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE
Persistence footer banner
Comments are closed on this article!