Slice 和 Page 之间的主要区别在于后者提供了重要的分页详细信息,例如记录总数(getTotalElements())、总页数(getTotalPages())和下一页可用性满足查询条件的状态(hasNext()),另一方面,前者仅提供分页详细信息,例如下一页可用性状态(hasNext())与其对应的Page相比。 Slice 在处理包含快速增长记录的巨大表时具有显着的性能优势。
让我们深入研究这两种变体的技术实现。
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());
}
}
如果观察上面的代码sn-p,PagedExecution#doExecute方法底层调用PagedExecution#count方法得到满足条件的记录总数。
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);
}
}
如果您观察上面的代码 sn-p,要找出是否存在下一组结果(对于hasNext()),SlicedExecution#doExecute 方法总是获取额外的一个元素(createQuery.setMaxResults(pageSize + 1))并根据pageSize 条件(hasNext ? resultList.subList(0, pageSize) : resultList)。
- 应用:
-
页面
当 UI/GUI 期望在搜索/查询本身的初始阶段显示所有结果时使用,并带有要遍历的页码(例如,带有页码的银行声明)
-
切片
当 UI/GUI 不希望在搜索/查询本身的初始阶段显示所有结果时使用,但意图显示基于滚动或下一步按钮单击事件遍历的记录(例如,facebook 提要搜索)