QueryDsl SpringData Jpa findAll如何避免count()

Eta*_*nio 5 java spring querydsl spring-data spring-data-jpa

我正在尝试将QueryDSL与Spring Data JPA一起使用,我想使用findAll分页,但是如果返回类型是a,则总是执行计数List.我不需要这个数,因为它真的很慢,我可以放弃分页的好处.

解决这个问题的方法有哪些

这就是count(),它需要大约30秒的MySQL:

Mysql在两个表之间的简单查询上太慢了

在任何情况下,我都不想重复我需要的每个页面的计数,这个信息只需要第一次调用.

Ali*_*ani 7

由于QueryDslPredicateExecutor不支持返回Slice作为返回值findAll(Predicate, Pageable),因此Count Query似乎不可避免.但是,您可以定义新的基本存储库接口,findAll并以不对分页发出计数查询的方式实现该方法.对于初学者,您应该定义一个接口,该接口将用作所有其他存储库的基本接口:

/**
 * Interface for adding one method to all repositories.
 *
 * <p>The main motivation of this interface is to provide a way
 * to paginate list of items without issuing a count query
 * beforehand. Basically we're going to get one element more
 * than requested and form a {@link Page} object out of it.</p>
 */
@NoRepositoryBean
public interface SliceableRepository<T, ID extends Serializable>
        extends JpaRepository<T, ID>,
        QueryDslPredicateExecutor<T> {

    Page<T> findAll(Predicate predicate, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

然后,实现此接口,如:

public class SliceableRepositoryImpl<T, ID extends Serializable>
        extends QueryDslJpaRepository<T, ID>
        implements SliceableRepository<T, ID> {
    private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
    private final EntityPath<T> path;
    private final PathBuilder<T> builder;
    private final Querydsl querydsl;

    public SliceableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        path = DEFAULT_ENTITY_PATH_RESOLVER.createPath(entityInformation.getJavaType());
        this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
        this.querydsl = new Querydsl(entityManager, builder);
    }

    @Override
    public Page<T> findAll(Predicate predicate, Pageable pageable) {
        int oneMore = pageable.getPageSize() + 1;
        JPQLQuery query = createQuery(predicate)
                .offset(pageable.getOffset())
                .limit(oneMore);

        Sort sort = pageable.getSort();
        query = querydsl.applySorting(sort, query);

        List<T> entities = query.list(path);

        int size = entities.size();
        if (size > pageable.getPageSize())
            entities.remove(size - 1);

        return new PageImpl<>(entities, pageable, pageable.getOffset() + size);
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,这个实现将获取比请求大小多一个元素并使用结果来构造一个Page.然后,您应该告诉Spring Data将此实现用作存储库基类:

@EnableJpaRepositories(repositoryBaseClass = SliceableRepositoryImpl.class)
Run Code Online (Sandbox Code Playgroud)

最后扩展SliceableRepository为您的基本界面:

public SomeRepository extends SliceableRepository<Some, SomeID> {}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。只记得 QueryDslPredicateExecutor 现在是 SpringBoot 2 中的 QuerydslPredicateExecutor (2认同)