1. 概要

この記事は、Hibernateでのページネーションの簡単な紹介です。 標準のHQLとScrollableResults APIを確認し、最後にHibernateCriteriaを使用したページ付けについて説明します。

2. HQLおよびsetFirstResult、 setMaxResultsAPIを使用したページ付け

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 エンティティを使用しており、JQL実装を使用したJPAと非常によく似ていますが、唯一の違いはクエリ言語です。

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. HQLとScrollableResultsAPIを使用したHibernateによるページネーション

ScrollableResul 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<Foo> fooPage = Lists.newArrayList();
int i = 0;
while (pageSize > i++) {
    fooPage.add((Foo) resultScroll.get(0));
    if (!resultScroll.next())
        break;
}

このメソッドは時間効率が良いだけでなく(データベース呼び出しが1回だけ)、ユーザーは追加のクエリなしで結果セットの合計カウントにアクセスできます。

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

一方、スクロールは非常に効率的ですが、大きなウィンドウはかなりの量のメモリを占める可能性があることに注意してください。

4. CriteriaAPIを使用したHibernateによるページネーション

最後に、より柔軟なソリューションを見てみましょう–基準を使用して:

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

Hibernate CriteriaクエリAPIを使用すると、 Projection オブジェクトを使用して、合計数を取得することも非常に簡単になります。

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

ご覧のとおり、このAPIを使用すると、プレーンなHQLよりも冗長なコードが最小限に抑えられますが、 APIは完全にタイプセーフであり、はるかに柔軟です

5. 結論

この記事は、Hibernateでページネーションを行うさまざまな方法の簡単な紹介です。

このSpringJPAチュートリアルの実装は、 GitHubプロジェクトにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。