Spring 数据 - 为什么无法使用本机查询进行分页

Spring Data - Why it's not possible to have paging with native query

假设我们有一个名为 MyEntity 的实体。可以使用 @Query 和命名查询来查询可分页的结果,例如

 @Query(value = "select e from MyEntity e where e.enabled = true")
 Page<MyEntity> findAllEnabled(Pageable pageable);

但是,用原生查询是不可能达到同样效果的,所以这个

 @Query(value = "select * from my_entity where enabled = true", nativeQuery = true)
 Page<MyEntity> findAllEnabled(Pageable pageable);

行不通。

这背后的原因是什么?是否可以使 Pageable 与本机查询一起使用?

这是描述,在 spring 数据 jpa 文档 (http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/)

中给出

Native queriesThe @Query annotation allows to execute native queries by setting the nativeQuery flag to true. Note, that we currently don’t support execution of pagination or dynamic sorting for native queries as we’d have to manipulate the actual query declared and we cannot do this reliably for native SQL.

JPQL 抽象了 SQL 实现及其提供者细节,并使 ORM 框架负责生成正确的 SQL.

  1. 所以通过使用JPQL形式的Pagination,Spring只需要生成正确的JPQL,它会在ORM层面被解释来纠正SQL。

  2. 虽然使用 SQL 这样做意味着 Spring 知道如何为绝大多数 RDBMS 生成正确的 SQL,复制 ORM 功能,这开销太大了。

我不知道这是否仍然与您相关:至少在 Spring Data JPA 1.9.4 中您可以指定两个查询。

给定一个存储库:

interface FoobarEntityRepository extends JpaRepository<FoobarEntity, Integer> {
    Page findFoobarsSpecialQuery(String someParameter, final Pageable pageable);
}

您可以向您的实体添加 2 个本机查询,一个用于查询本身,一个用于计数语句:

@Entity
@SqlResultSetMappings({
    @SqlResultSetMapping(name = "SqlResultSetMapping.count", columns = @ColumnResult(name = "cnt"))
})
@NamedNativeQueries({
    @NamedNativeQuery(
            name = "FoobarEntity.findFoobarsSpecialQuery",
            resultClass = DailyPictureEntity.class,
            query = "Select * from foobars f where someValue = :someParameter "
    ),
    @NamedNativeQuery(
            name = "FoobarEntity.findFoobarsSpecialQuery.count",
            resultSetMapping = "SqlResultSetMapping.count",
            query = "Select count(*) as cnt from foobars f where someValue = :someParameter "
    )
})
FoobarEntity {
}

诀窍是使用后缀 .count 指定计数查询。这也适用于 Spring Data @Query 注释。

请注意,您需要一个 SQL 结果集映射来进行计数查询。

这确实很好用。

有一种方法可以将 Pageable 与具有 Spring 数据的 SpEL 容量的本机查询一起使用,提到 here

您可以在 this repository 中找到示例。

/**
     * @see DATAJPA-564
     */
    @Query(
            value = "select * from (select rownum() as RN, u.* from SD_User u) where RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize}",
            countQuery = "select count(u.id) from SD_User u", nativeQuery = true)
    Page<User> findUsersInNativeQueryWithPagination(Pageable pageable);

如果 from 子句或您的本机查询中有子查询并且您希望对其应用动态排序,则排序功能将无法正常工作。可以做到的方法是在 where 子句中移动子查询。
如果 Pageable 中有 Sort 对象,Spring 数据将附加到请求 " order by "end。 (使用 Spring 数据 1.10.3)

如果可能,更好的方法是在 jpql 中转换本机查询。