Spring Data JPA 分页 HHH000104

Tho*_*ang 5 hibernate jpa spring-data-jpa spring-boot

我得到了这个存储库代码:

\n
@Query(value = "select distinct r from Reference r " +\n        "inner join fetch r.persons " +\n        "left outer join fetch r.categories " +\n        "left outer join fetch r.keywords " +\n        "left outer join fetch r.parentReferences",\n        countQuery = "select count(distinct r.id) from Reference r " +\n                "inner join r.persons " +\n                "left outer join r.categories " +\n                "left outer join r.keywords " +\n                "left outer join r.parentReferences")\nPage<Reference> findsAllRelevantEntries(Pageable pageable);\n
Run Code Online (Sandbox Code Playgroud)\n

当我对该查询运行测试时,我收到此 Hibernate 警告:
\nHHH000104: firstResult/maxResults specified with collection fetch; applying in memory!

\n
@Test\nvoid testFindAllRelevantAsync() throws ExecutionException, InterruptedException {\n    CompletableFuture<Page<Reference>> all = referenceService.findAllRelevantAsync(PageRequest.of(1, 20));\n    CompletableFuture.allOf(all).join();\n    assertThat(all.get()).isNotNull();\n    assertThat(all.get()).isNotEmpty();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

存储库代码封装在此处未显示的服务方法中。它(服务方法)只是将服务的调用编组到存储库并返回。

\n

此外,生成的 sql 查询不会生成limit子句。尽管它确实引发了两个查询。

\n

一个用于count,另一个用于获取所有记录。
\n因此它会获取所有记录并在内存中应用分页。
\n这会导致查询执行速度非常慢。

\n

我怎样才能使分页与此查询一起使用?

\n

编辑

\n

我知道这里经常建议作为解决方案:\n如何避免警告“使用集合获取指定的firstResult/maxResults;在内存中应用!” 当使用休眠时?

\n

有没有办法使用 Spring Data JPA 实现分页?\n我不想\xc2\xb4t 想要硬连线 an EntityManager,也不想\n从 a 扩展代码BasicTransformerAdapter

\n

Tho*_*ang 1

我自己找到了解决方法。基于此:
如何避免警告“使用集合获取指定的firstResult/maxResults;在内存中应用!” 当使用休眠时?

首先:通过分页获取Id:

@Query(value = "select distinct r.id from Reference r " +
        "inner join r.persons " +
        "left outer join r.categories " +
        "left outer join r.keywords " +
        "left outer join r.parentReferences " +
        "order by r.id",
        countQuery = "select count(distinct r.id) from Reference r " +
                "inner join r.persons " +
                "left outer join r.categories " +
                "left outer join r.keywords " +
                "left outer join r.parentReferences " +
                "order by r.id")
Page<UUID> findsAllRelevantEntriesIds(Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

第二:使用Id进行in查询

@Query(value = "select distinct r from Reference r " +
        "inner join fetch r.persons " +
        "left outer join fetch r.categories " +
        "left outer join fetch r.keywords " +
        "left outer join fetch r.parentReferences " +
        "where r.id in ?1 " +
        "order by r.id",
        countQuery = "select count(distinct r.id) from Reference r " +
                "inner join r.persons " +
                "left outer join r.categories " +
                "left outer join r.keywords " +
                "left outer join r.parentReferences ")
@QueryHints(value = {@QueryHint(name = "hibernate.query.passDistinctThrough", value = "false")},
        forCounting = false)
List<Reference> findsAllRelevantEntriesByIds(UUID[] ids);
Run Code Online (Sandbox Code Playgroud)

注意: 我得到的List<Reference不是 a,Pageable所以你必须Pageable自己构建,如下所示:

private Page<Reference> processResults(Pageable pageable, Page<UUID> result) {
    List<Reference> references = referenceRepository.findsAllRelevantEntriesByIds(result.toList().toArray(new UUID[0]));
    return new PageImpl<>(references, pageable, references.size());
}
Run Code Online (Sandbox Code Playgroud)

这看起来不太好,并且执行了两个语句,但它使用 进行查询limit,因此仅获取所需的记录。