Paginação JPA

Paginação JPA

1. Visão geral

Este artigo ilustra como implementarpagination in the Java Persistence API.

Ele explica como fazer paginação com JQL básico e com as APIs baseadas em critérios mais seguras de tipo, discutindo as vantagens e os problemas conhecidos de cada implementação.

Leitura adicional:

Paginação com Spring REST e tabela AngularJS

Uma visão abrangente de como implementar uma API simples com paginação com Spring e como consumi-la com AngularJS e UI Grid.

Read more

Spring JPA - vários bancos de dados

Como configurar o Spring Data JPA para trabalhar com vários bancos de dados separados.

Read more

Dados da Primavera JPA @Query

Aprenda a usar a anotação @Query no Spring Data JPA para definir consultas personalizadas usando JPQL e SQL nativo.

Read more

2. Paginação com JQL esetFirstResult(),setMaxResults() API

A maneira mais simples de implementar a paginação é usarthe Java Query Language - crie uma consulta e configure-a viasetMaxResults ** esetFirstResult:

Query query = entityManager.createQuery("From Foo");
int pageNumber = 1;
int pageSize = 10;
query.setFirstResult((pageNumber-1) * pageSize);
query.setMaxResults(pageSize);
List  fooList = query.getResultList();

A API é simples:

  • *setFirstResult(int*): Define a posição de deslocamento no conjunto de resultados para iniciar a paginação

  • setMaxResults(int): Define o número máximo de entidades que devem ser incluídas na página

2.1. A contagem total e a última página

Para uma solução de paginação mais completa, também precisaremos obterthe total result count:

Query queryTotal = entityManager.createQuery
    ("Select count(f.id) from Foo f");
long countResult = (long)queryTotal.getSingleResult();

Calcularthe last page também é muito útil:

int pageSize = 10;
int pageNumber = (int) ((countResult / pageSize) + 1);

Observe que essa abordagem para obter a contagem total do conjunto de resultados requer uma consulta adicional (para a contagem).

3. Paginação com JQL usando os IDs de entidades

Uma estratégia de paginação alternativa simples éfirst retrieve the full idse então - com base neles -retrieve the full entities. Isso permite um melhor controle da busca da entidade - mas também significa que ele precisa carregar a tabela inteira para recuperar os IDs:

Query queryForIds = entityManager.createQuery(
  "Select f.id from Foo f order by f.lastName");
List 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 fooList = query.getResultList();

Por fim, observe também que são necessárias duas consultas distintas para recuperar os resultados completos.

4. Paginação com JPA usando Criteria API

A seguir, vamos ver como podemosleverage the JPA Criteria API para implementar a paginação:

int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager
  .getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder
  .createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
TypedQuery typedQuery = entityManager.createQuery(select);
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(pageSize);
List fooList = typedQuery.getResultList();

Isso é útil quando o objetivo é criar consultas dinâmicas e sem falhas. Em contraste com as consultas JQL ou HQL “codificadas”, “baseadas em string”,JPA Criteria reduz as falhas de tempo de execução porque o compilador verifica dinamicamente se há erros de consulta.

Com os critérios JPAgetting the total number of entities bastante simples:

CriteriaQuery countQuery = criteriaBuilder
  .createQuery(Long.class);
countQuery.select(criteriaBuilder.count(
  countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
  .getSingleResult();

O resultado final éa full pagination solution, usando a API de critérios JPA:

int pageNumber = 1;
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

CriteriaQuery countQuery = criteriaBuilder
  .createQuery(Long.class);
countQuery.select(criteriaBuilder
  .count(countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
  .getSingleResult();

CriteriaQuery criteriaQuery = criteriaBuilder
  .createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);

TypedQuery typedQuery = entityManager.createQuery(select);
while (pageNumber < count.intValue()) {
    typedQuery.setFirstResult(pageNumber - 1);
    typedQuery.setMaxResults(pageSize);
    System.out.println("Current page: " + typedQuery.getResultList());
    pageNumber += pageSize;
}

5. Conclusão

Este artigo explorou as opções básicas de paginação disponíveis no JPA.

Alguns têm desvantagens - principalmente relacionadas ao desempenho da consulta, mas geralmente são compensadas pelo controle aprimorado e pela flexibilidade geral.

A implementação deste tutorial do Spring JPA pode ser encontrada emthe GitHub project - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.