【问题标题】:Page<> vs Slice<> when to use which?Page<> vs Slice<> 什么时候使用?
【发布时间】:2018-04-19 10:37:24
【问题描述】:

我在 Spring Jpa Data documentation 中读到了两种不同类型的对象,当您“分页”由存储库生成的动态查询时。

页面切片

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

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

所以,我试图找到一些文章或任何东西来讨论两者的主要区别和不同的用法性能如何变化以及排序 strong> 影响这两种类型的查询。

有没有人拥有这类知识、文章或一些好的信息来源?

【问题讨论】:

  • 我敢打赌Page 会触发一个额外的count 查询以了解页面/元素的总数,而Slice 不会。
  • 我同意@sp00m。实际上,当您查看源代码时,Page 正在实现 Slice。因此,从性能的角度来看,您应该在需要总计数时使用 Page,否则应使用 Slice。
  • 您已接受不处理“排序”问题的答案 - 例如。添加排序操作时,Slice 和 Page 的行为如何。当涉及到排序时,您是否发现它们之间是否有任何区别?我问这个是因为排序也意味着完整读取记录。

标签: java spring spring-data spring-data-jpa


【解决方案1】:

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

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

【讨论】:

  • 是的,我读过。我想知道差异是否比这更大,但正如我所见,事实并非如此。这个答案似乎就足够了:) 感谢所有
  • Slice has information about whether the next or previous object exists or not. 使用Page时发现有问题
  • @cassiomolin,从 repo 方法返回 List 是否比 Slice 性能更高,当然还有 Page
  • 但是如果Page和Slice都按顺序下单,有什么区别吗?
【解决方案2】:

SlicePage 之间的主要区别在于后者提供了重要的分页详细信息,例如记录总数(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 提要搜索)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-09
    • 2015-05-14
    • 2018-10-28
    • 2021-02-01
    • 2015-10-27
    • 2011-08-17
    • 2013-09-14
    • 1970-01-01
    相关资源
    最近更新 更多