1.概述
本文说明了如何在Java Persistence API中实现分页。
它解释了如何使用基本JQL进行分页,以及使用更加类型安全的基于Criteria的API,讨论每个实现的优点和已知问题。
2.使用JQL和setFirstResult(),setMaxResults() API进行分页
实现分页的最简单方法是使用Java查询语言 - 创建查询并通过setMaxResults 和s e tFirstResult进行配置:
Query query = entityManager.createQuery("From Foo");
int pageNumber = 1;
int pageSize = 10;
query.setFirstResult((pageNumber-1) * pageSize);
query.setMaxResults(pageSize);
List <Foo> fooList = query.getResultList();
API很简单:
- setFirstResult(int):设置结果集中的偏移位置以开始分页
- setMaxResults(int):设置应包含在页面中的最大实体数
2.1。总计数和最后一页
要获得更完整的分页解决方案,我们还需要获得总结果数:
Query queryTotal = entityManager.createQuery
("Select count(f.id) from Foo f");
long countResult = (long)queryTotal.getSingleResult();
计算最后一页也非常有用:
int pageSize = 10;
int pageNumber = (int) ((countResult / pageSize) + 1);
请注意,这种获取结果集总计数的方法确实需要额外的查询(对于计数)。
3.使用实体的Id进行JQL分页
一个简单的替代分页策略是首先检索完整的ID然后 - 基于这些 - 检索完整的实体。这允许更好地控制实体获取 - 但这也意味着它需要加载整个表来检索id:
Query queryForIds = entityManager.createQuery(
"Select f.id from Foo f order by f.lastName");
List<Integer> fooIds = queryForIds.getResultList();
Query query = entityManager.createQuery(
"Select f from Foo e where f.id in :ids");
query.setParameter("ids", fooIds.subList(0,10));
List<Foo> fooList = query.getResultList();
最后,还要注意,它需要2个不同的查询来检索完整的结果。
4.使用Criteria API对JPA进行分页
接下来,让我们看看我们如何利用JPA Criteria API来实现分页:
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager
.getCriteriaBuilder();
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder
.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
TypedQuery<Foo> typedQuery = entityManager.createQuery(select);
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(pageSize);
List<Foo> fooList = typedQuery.getResultList();
当目标是创建动态的,故障安全查询时,这非常有用。与“硬编码”,“基于字符串”的JQL或HQL查询相比,JPA Criteria减少了运行时故障,因为编译器会动态检查查询错误。
使用JPA Criteria 可以获得足够简单的实体总数:
CriteriaQuery<Long> countQuery = criteriaBuilder
.createQuery(Long.class);
countQuery.select(criteriaBuilder.count(
countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
.getSingleResult();
最终结果是使用JPA Criteria API 的完整分页解决方案:
int pageNumber = 1;
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> countQuery = criteriaBuilder
.createQuery(Long.class);
countQuery.select(criteriaBuilder
.count(countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
.getSingleResult();
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder
.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
TypedQuery<Foo> typedQuery = entityManager.createQuery(select);
while (pageNumber < count.intValue()) {
typedQuery.setFirstResult(pageNumber - 1);
typedQuery.setMaxResults(pageSize);
System.out.println("Current page: " + typedQuery.getResultList());
pageNumber += pageSize;
}