Como esta es una pregunta muy común, escribí
este artículo , en el que se basa esta respuesta.
Los setFirstResult
y setMaxResults
Query
métodos
Para un JPA e Hibernate Query
, el setFirstResult
método es el equivalente de OFFSET
, y el setMaxResults
método es el equivalente de LIMIT:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
La LimitHandler
abstraccion
Hibernate LimitHandler
define la lógica de paginación específica de la base de datos y, como se ilustra en el siguiente diagrama, Hibernate admite muchas opciones de paginación específicas de la base de datos:
Ahora, dependiendo del sistema de base de datos relacional subyacente que esté utilizando, la consulta JPQL anterior utilizará la sintaxis de paginación adecuada.
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_ > ?
La ventaja de usar setFirstResult
y setMaxResults
es que Hibernate puede generar la sintaxis de paginación específica de la base de datos para cualquier base de datos relacional compatible.
Y no está limitado únicamente a consultas JPQL. Puede usar el método setFirstResult
y setMaxResults
siete para consultas SQL nativas.
Consultas SQL nativas
No tiene que codificar la paginación específica de la base de datos cuando utiliza consultas SQL nativas. Hibernate puede agregar eso a sus consultas.
Entonces, si está ejecutando esta consulta SQL en 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();
Hibernate lo transformará de la siguiente manera:
SELECT p.id AS id,
p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
¿Guay, verdad?
Más allá de la paginación basada en SQL
La paginación es buena cuando puede indexar los criterios de filtrado y clasificación. Si sus requisitos de paginación implican un filtrado dinámico, es un enfoque mucho mejor utilizar una solución de índice invertido, como ElasticSearch.
Mira este artículo para más detalles.
Hibernate-5.0.12
. ¿Todavía no está disponible? Sería realmente pesado obtener un millón de registros y luego aplicar el filtrosetMaxResults
sobre él, como notó @Rachel en la respuesta de @skaffman.