Como essa é uma pergunta muito comum, escrevi
este artigo , no qual essa resposta se baseia.
Os métodos setFirstResult
esetMaxResults
Query
Para uma JPA e Hibernate Query
, o setFirstResult
método é equivalente ae OFFSET
o setMaxResults
método é equivalente a LIMIT:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
A LimitHandler
abstração
O Hibernate LimitHandler
define a lógica de paginação específica do banco de dados e, conforme ilustrado no diagrama a seguir, o Hibernate suporta muitas opções de paginação específicas do banco de dados:
Agora, dependendo do sistema de banco de dados relacional subjacente que você estiver usando, a consulta JPQL acima usará a sintaxe de paginação apropriada.
MySQL
SELECT p.id AS id1_0_,
p.created_on AS created_2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?, ?
PostgreSQL
SELECT p.id AS id1_0_,
p.created_on AS created_2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
servidor SQL
SELECT p.id AS id1_0_,
p.created_on AS created_on2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
OFFSET ? ROWS
FETCH NEXT ? ROWS ONLY
Oráculo
SELECT *
FROM (
SELECT
row_.*, rownum rownum_
FROM (
SELECT
p.id AS id1_0_,
p.created_on AS created_on2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
) row_
WHERE rownum <= ?
)
WHERE rownum_ > ?
A vantagem de usar setFirstResult
e setMaxResults
é que o Hibernate pode gerar a sintaxe de paginação específica do banco de dados para qualquer banco de dados relacional suportado.
E você não está limitado apenas às consultas JPQL. Você pode usar o método setFirstResult
e setMaxResults
sete para consultas SQL nativas.
Consultas SQL nativas
Você não precisa codificar a paginação específica do banco de dados ao usar consultas SQL nativas. O Hibernate pode adicionar isso às suas consultas.
Portanto, se você estiver executando esta consulta SQL no PostgreSQL:
List<Tuple> posts = entityManager
.createNativeQuery(
"SELECT " +
" p.id AS id, " +
" p.title AS title " +
"from post p " +
"ORDER BY p.created_on", Tuple.class)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
O Hibernate irá transformá-lo da seguinte maneira:
SELECT p.id AS id,
p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
Legal certo?
Além da paginação baseada em SQL
A paginação é boa quando você pode indexar os critérios de filtragem e classificação. Se seus requisitos de paginação implicam filtragem dinâmica, é uma abordagem muito melhor usar uma solução de índice invertido, como o ElasticSearch.
Confira este artigo para mais detalhes.
Hibernate-5.0.12
. Isso ainda não está disponível? Seria muito pesado obter um milhão de registros e, em seguida, aplicar o filtro sobre elesetMaxResults
, como observado por Rachel na resposta de @skaffman.