休止状態のページネーション
1. 概要
この記事は簡単なintroduction to Pagination in Hibernateです。 標準のHQLとScrollableResults APIを確認し、最後にHibernateCriteriaを使用したページ付けについて説明します。
参考文献:
Spring BootからのHibernate / JPA SQLステートメントの表示
Spring Bootアプリケーションで生成されたSQLステートメントのロギングを構成する方法を学びます。
2. HQLおよびsetFirstResult、setMaxResultsAPIによるページ付け
Hibernateでページネーションを行う最も簡単で一般的な方法はusing HQLです。
Session session = sessionFactory.openSession();
Query query = sess.createQuery("From Foo");
query.setFirstResult(0);
query.setMaxResults(10);
List fooList = fooList = query.list();
この例では、基本的なFooエンティティーを使用しており、JQL実装のJPAと非常によく似ています。唯一の違いは、クエリ言語です。
logging for Hibernateをオンにすると、次のSQLが実行されていることがわかります。
Hibernate:
select
foo0_.id as id1_1_,
foo0_.name as name2_1_
from
Foo foo0_ limit ?
2.1. 総数と最後のページ
ページネーションソリューションは、the total number of entitiesを知らなければ完全ではありません。
String countQ = "Select count (f.id) from Foo f";
Query countQuery = session.createQuery(countQ);
Long countResults = (Long) countQuery.uniqueResult();
そして最後に、総数と指定されたページサイズから、the last pageを計算できます。
int pageSize = 10;
int lastPageNumber = (int) (Math.ceil(countResults / pageSize));
この時点で、a complete example for paginationを確認できます。ここで、最後のページを計算して取得しています。
@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. HQLとScrollableResults APIを使用したHibernateによるページ付け
ScrollableResultsを使用してページネーションを実装すると、reduce database callsになる可能性があります。 このアプローチでは、プログラムがスクロールするときに結果セットがストリーミングされるため、クエリを繰り返して各ページを埋める必要がなくなります。
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;
}
このメソッドは、時間効率が良い(1回のデータベース呼び出しのみ)だけでなく、ユーザーがtotal count of the result set without an additional queryにアクセスできるようにします。
resultScroll.last();
int totalResults = resultScroll.getRowNumber() + 1;
一方、スクロールは非常に効率的ですが、大きなウィンドウはかなりの量のmemoryを占める可能性があることに注意してください。
4. Criteria APIを使用したHibernateによるページ付け
最後に、基準を使用してa more flexible solutionを見てみましょう。
Criteria criteria = session.createCriteria(Foo.class);
criteria.setFirstResult(0);
criteria.setMaxResults(pageSize);
List firstPage = criteria.list();
Hibernate CriteriaクエリAPIを使用すると、Projectionオブジェクトを使用してget the total countも非常に簡単になります。
Criteria criteriaCount = session.createCriteria(Foo.class);
criteriaCount.setProjection(Projections.rowCount());
Long count = (Long) criteriaCount.uniqueResult();
ご覧のとおり、このAPIを使用すると、プレーンなHQLよりも冗長なコードが最小限になりますが、the API is fully type safe and a lot more flexibleになります。
5. 結論
この記事は、Hibernateでページネーションを行うさまざまな方法の簡単な紹介です。
このSpringJPAチュートリアルの実装はthe GitHub projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。