这些方法带有 JpaSpecificationExecutor不够,他们都没有给我我想要的:
Page<T> findAll(Specification<T> spec, Pageable pageable)
List<T> findAll(Specification<T> spec)
List<T> findAll(Specification<T> spec, Sort sort)
第一个方法执行分页查询和计数查询。接下来的 2 个根本不执行分页。我需要的是以下之一:
Slice<T> findAll(Specification<T> spec, Pageable pageable)
List<T> findAll(Specification<T> spec, Pageable pageable)
通过不扩展 JpaSpecificationExecutor,我能够执行两个查询,但计数查询也是如此。在我的情况下,必须避免计数查询,因为它非常昂贵。问题是如何?
最佳答案
查看 SimpleJpaRepository的 findAll(Specification, Pageable)
和 readPage(TypedQuery, Pageable, Specific)
方法。看来Spring的实现是在执行select查询之前总是执行计数查询并检查startIndex是否超出范围:
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
Long total = QueryUtils.executeCountQuery(getCountQuery(spec));
List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T> emptyList();
return new PageImpl<T>(content, pageable, total);
}
我不认为这始终是最佳实践。例如,在我的用例中,我们很乐意预先执行一次计数查询,而不是在后续调用中执行,因为我们知道新数据的出现频率不足以保证计数更新,并且执行计数查询的成本非常昂贵。
如果 Spring Data 可以提供一个标志或替代方法来禁用条件查询的计数,那就太好了,类似于 simple find queries 。
同时,这是我的解决方案:
创建一个子类 SimpleJpaRepository 的内部类。重写 readPage 以禁用计数查询。创建一个 DAO,用 @Repository 注释它并实例化这个内部类以传递正确的 EntityManager。最后,在适用“无计数”条件搜索的地方注入(inject)此 DAO:
@Repository
public class CriteriaNoCountDao {
@PersistenceContext
protected EntityManager em;
public <T, ID extends Serializable> Page<T> findAll(Specification<T> spec, Pageable pageable, Class<T> clazz){
SimpleJpaNoCountRepository<T, ID> noCountDao = new SimpleJpaNoCountRepository<T, ID>(clazz, em);
return noCountDao.findAll(spec, pageable);
}
/**
* Custom repository type that disable count query.
*/
public static class SimpleJpaNoCountRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
public SimpleJpaNoCountRepository(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
/**
* Override {@link SimpleJpaRepository#readPage(TypedQuery, Pageable, Specification)}
*/
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
List<T> content = query.getResultList();
return new PageImpl<T>(content, pageable, content.size());
}
}
}
关于spring - 当Specification和Pageable一起使用时如何禁用计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60591109/