Page<> vs Slice<> when to use which?
Page
extends Slice
and knows the total number of elements and pages available by triggering a count query. From the Spring Data JPA documentation:
A
Page
knows about the total number of elements and pages available. It does so by the infrastructure triggering a count query to calculate the overall number. As this might be expensive depending on the store used,Slice
can be used as return instead. ASlice
only knows about whether there’s a nextSlice
available which might be just sufficient when walking through a larger result set.
The main difference between Slice
and Page
is the latter provides non-trivial pagination details such as total number of records(getTotalElements()
), total number of pages(getTotalPages()
), and next-page availability status(hasNext()
) that satisfies the query conditions, on the other hand, the former only provides pagination details such as next-page availability status(hasNext()
) compared to its counterpart Page
. Slice
gives significant performance benefits when you deal with a colossal table with burgeoning records.
Let's dig deeper into its technical implementation of both variants.
- Page
static class PagedExecution extends JpaQueryExecution {
@Override
protected Object doExecute(final AbstractJpaQuery repositoryQuery, JpaParametersParameterAccessor accessor) {
Query query = repositoryQuery.createQuery(accessor);
return PageableExecutionUtils.getPage(query.getResultList(), accessor.getPageable(),
() -> count(repositoryQuery, accessor));
}
private long count(AbstractJpaQuery repositoryQuery, JpaParametersParameterAccessor accessor) {
List<?> totals = repositoryQuery.createCountQuery(accessor).getResultList();
return (totals.size() == 1 ? CONVERSION_SERVICE.convert(totals.get(0), Long.class) : totals.size());
}
}
If you observe the above code snippet, PagedExecution#doExecute method underlyingly calls PagedExecution#count method to get the total number of records satisfying the condition.
- Slice
static class SlicedExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
Pageable pageable = accessor.getPageable();
Query createQuery = query.createQuery(accessor);
int pageSize = 0;
if (pageable.isPaged()) {
pageSize = pageable.getPageSize();
createQuery.setMaxResults(pageSize + 1);
}
List<Object> resultList = createQuery.getResultList();
boolean hasNext = pageable.isPaged() && resultList.size() > pageSize;
return new SliceImpl<>(hasNext ? resultList.subList(0, pageSize) : resultList, pageable, hasNext);
}
}
If you observe the above code snippet, to findout whether next set of results present or not (for hasNext()
) the SlicedExecution#doExecute
method always fetch extra one element(createQuery.setMaxResults(pageSize + 1)
) and skip it based on the pageSize condition(hasNext ? resultList.subList(0, pageSize) : resultList
).
- Application:
Page
Use when UI/GUI expects to displays all the results at the initial stage of the search/query itself, with page numbers to traverse(ex., bankStatement with pagenumbers)
Slice
Use when UI/GUI expects to doesnot interested to show all the results at the initial stage of the search/query itself, but intent to show the records to traverse based on scrolling or next button click event (ex., facebook feed search)