Slice
和
Page
的主要区别在于后者提供了非平凡的分页详细信息,例如记录总数(
getTotalElements()
)、页面总数(
getTotalPages()
)以及满足查询条件的下一页可用状态(
hasNext()
),而前者则仅与其对应的
Page
相比提供了下一页可用状态(
hasNext()
)等分页详细信息。当你处理庞大的表格并且有大量记录时,
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());
}
}
如果您观察上面的代码片段,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);
}
}
如果您观察上面的代码片段,要查找下一组结果是否存在(对于
hasNext()
),
SlicedExecution#doExecute
方法总是获取多一个元素(
createQuery.setMaxResults(pageSize + 1)
)并根据 pageSize 条件跳过它(
hasNext ? resultList.subList(0, pageSize) : resultList
)。
应用:
- 页面:
- 当 UI/GUI 希望在搜索/查询的初始阶段就显示所有结果,并提供页面号码进行遍历时使用(例如带有页面号码的银行对账单)。
- 切片:
- 当 UI/GUI 不希望在搜索/查询的初始阶段显示所有结果,而是打算根据滚动或点击下一个按钮事件来显示记录时使用(例如 Facebook 动态源搜索)。
Page
会触发额外的count
查询来获取总页数或元素数,而Slice
则不会。 - sp00m