Page<> vs Slice<>何时使用哪个?

2022-09-01 05:22:29

我在Spring Jpa Data文档中读到过两种不同类型的对象,当您从存储库中“分页”动态查询时。

页面切片

Page<User> findByLastname(String lastname, Pageable pageable);

Slice<User> findByLastname(String lastname, Pageable pageable); 

因此,我试图找到一些文章或任何关于两者的主要区别和不同用法的文章,性能如何变化以及排序如何同时处理这两种类型的查询。

有没有人有这种类型的知识,文章或一些好的信息来源?


答案 1

Page 扩展 Slice,并通过触发计数查询了解可用的元素和页面的总数。来自Spring Data JPA文档

A 知道可用的元素和页面的总数。它通过基础结构触发计数查询来计算总数来实现此目的。由于这可能会很昂贵,具体取决于所使用的商店,因此可以用作退货。只有 A 知道是否有下一个可用,这在遍历更大的结果集时可能就足够了。PageSliceSliceSlice


答案 2

和 之间的主要区别在于后者提供了不平凡的分页详细信息,例如满足查询条件的记录总数(),总页数()和下一页可用性状态(),另一方面,前者仅提供分页详细信息,例如下一页可用性状态()与其对应项相比。 当您处理具有新兴记录的巨大表时,可提供显著的性能优势。SlicePagegetTotalElements()getTotalPages()hasNext()hasNext()PageSlice

让我们更深入地了解这两种变体的技术实现。

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);

    }
}

如果您观察上面的代码片段,为了找出下一组结果是否存在(对于),该方法总是获取额外的一个element()并根据pageSize condition()跳过它。hasNext()SlicedExecution#doExecutecreateQuery.setMaxResults(pageSize + 1)hasNext ? resultList.subList(0, pageSize) : resultList

  • 应用:
    • 当UI/GUI期望在搜索/查询本身的初始阶段显示所有结果,并带有要遍历的页码(例如,带有页码的bankStatement)时使用

    • 当 UI/GUI 不希望在搜索/查询本身的初始阶段显示所有结果,而是打算根据滚动或下一个按钮单击事件(例如,Facebook 源搜索)显示要遍历的记录时使用


推荐