具有分页的Spring Data和Native Query

Las*_*eyx 52 spring spring-data spring-data-jpa

在一个Web项目中,使用最新的spring-data(1.10.2)和MySQL 5.6数据库,我正在尝试使用带有分页的本机查询,但我org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException在启动时遇到了问题.

更新:20180306此问题现已在Spring 2.0.4中修复.对于那些仍然感兴趣或坚持使用旧版本的用户,请查看相关的答案和注释以获取解决方法.

根据Spring-data文档中使用@Query的示例50,可以指定查询本身和countQuery,如下所示:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

出于好奇,在NativeJpaQuery课堂上我可以看到它包含以下代码来检查它是否是一个有效的jpa查询:

public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
   super(method, em, queryString, evaluationContextProvider, parser);
   JpaParameters parameters = method.getParameters();
   boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter();
   boolean containsPageableOrSortInQueryExpression = queryString.contains("#pageable") || queryString.contains("#sort");
   if(hasPagingOrSortingParameter && !containsPageableOrSortInQueryExpression) {
       throw new InvalidJpaQueryMethodException("Cannot use native queries with dynamic sorting and/or pagination in method " + method);
   }
}
Run Code Online (Sandbox Code Playgroud)

我的查询包含一个Pageable参数,所以hasPagingOrSortingParametertrue,但它也在查找内部#pageable#sort序列queryString,我没有提供.

我在#pageable我的查询结束时尝试添加(这是一个注释),这使得验证通过但是,它在执行时失败,说查询需要一个额外的参数:3而不是2.

有趣的是,如果我手动更改containsPageableOrSortInQueryExpression来自falsetrue在运行时,查询工作正常,所以我不知道为什么它检查该字符串是我的queryString,我不知道如何规定的.

任何帮助将非常感激.

更新01/30/2018 似乎spring-data项目的开发人员正在通过Jens SchauderPR解决此问题

Ema*_*sco 35

我提前道歉,这几乎总结了原始问题和Janar的评论,但......

我遇到了同样的问题:我发现Spring Data示例50作为我需要使用分页的本机查询的解决方案,但Spring在启动时抱怨我不能使用本机查询的分页.

我只想报告我成功运行了我需要的本机查询,使用分页,使用以下代码:

    @Query(value="SELECT a.* "
            + "FROM author a left outer join mappable_natural_person p on a.id = p.provenance_id "
            + "WHERE p.update_time is null OR (p.provenance_name='biblio_db' and a.update_time>p.update_time)"
            + "ORDER BY a.id \n#pageable\n", 
        /*countQuery="SELECT count(a.*) "
            + "FROM author a left outer join mappable_natural_person p on a.id = p.provenance_id "
            + "WHERE p.update_time is null OR (p.provenance_name='biblio_db' and a.update_time>p.update_time) \n#pageable\n",*/
        nativeQuery=true)
public List<Author> findAuthorsUpdatedAndNew(Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

countQuery(在代码块中注释掉)需要Page<Author> 用作查询的返回类型,需要围绕"#pageable"注释的换行符以避免预期参数数量的运行时错误(解决方法)解决方法).我希望很快就会修复这个bug ...

  • 这有效.对于参数,您仍然可以使用命名参数.例如`:authorId`.我将你的`\n#pageable \n`更改为` - #pageable \n`为postgresql.如你所建议的那样需要countQuery,因为很多例子使用List <>而不是Page <>你的答案就是这个.我经历了相同的文档,如果不是你的答案,我会放弃. (6认同)
  • 如果您不编写 countQuery 并让框架处理它,有时不会为您正确编写按查询计数,您可能会看到错误为无效字段列表。您始终可以通过将以下条目添加到属性文件 logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 来分析 SQL 语句,单独添加查询计数将解决问题。这可能取决于您使用的框架版本和数据库。 (2认同)

Dmi*_*bov 24

此代码与PostgreSQL和MySQL一起使用:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY ?#{#pageable}",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

ORDER BY ?#{#pageable}是为了Pageable. countQuery是为了Page<>.


Tim*_*sen 20

我添加这个答案只是作为那些使用较新版本的 Spring Boot 的用户的占位符。在 Spring Boot 2.4.3 上,我发现没有任何解决方法是必要的,并且以下代码对我来说直接可用:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value="SELECT * FROM USERS WHERE LASTNAME = ?1", nativeQuery=true)
    Page<User> findByLastname(String lastname, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

countQuery定义不是必需的,事实上调用Page#getTotalElements()已经返回了正确的计数,正如 JPA 自己的内部计数查询所返回的那样。

上面的代码非常强大,提供通过本机查询进行的分页,但将结果返回到实际的 Java 实体中(而不是丑陋且庞大的List<Object[]>,这有时是必要的)。

  • 但是当我使用别名时,我必须添加 countQuery 否则我得到 oracle.jdbc.OracleDatabaseException: ORA-00904: "myAlias" invalididentifier (3认同)

mar*_*icn 10

只是为了记录,使用H2作为测试数据库,并在运行时使用MySQL,这种方法可行(例如,组中的最新对象):

@Query(value = "SELECT t.* FROM t LEFT JOIN t AS t_newer " +
        "ON t.object_id = t_newer.object_id AND t.id < t_newer.id AND o_newer.user_id IN (:user_ids) " +
        "WHERE t_newer.id IS NULL AND t.user_id IN (:user_ids) " +
        "ORDER BY t.id DESC \n-- #pageable\n",
        countQuery = "SELECT COUNT(1) FROM t WHERE t.user_id IN (:user_ids) GROUP BY t.object_id, t.user_id",
        nativeQuery = true)
Page<T> findByUserIdInGroupByObjectId(@Param("user_ids") Set<Integer> userIds, Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

Spring Data JPA 1.10.5,H2 1.4.194,MySQL Community Server 5.7.11-log(innodb_version 5.7.11).


689*_*689 6

我有类似@Lasneyx的完全相同的症状.我对Postgres本机查询的解决方法

@Query(value = "select * from users where user_type in (:userTypes) and user_context='abc'--#pageable\n", nativeQuery = true)
List<User> getUsersByTypes(@Param("userTypes") List<String> userTypes, Pageable pageable);
Run Code Online (Sandbox Code Playgroud)


小智 5

试试这个:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY /*#pageable*/",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

("/* */"用于Oracle notation)

  • 在我不得不按条款处理订单之后它起作用了 (2认同)

Lev*_*_Up 5

我使用 oracle 数据库,但没有得到结果,但生成的逗号错误,d-man 在上面谈到了这个错误。

然后我的解决方案是:

Pageable pageable = new PageRequest(current, rowCount);
Run Code Online (Sandbox Code Playgroud)

正如您在创建 Pagable 时无序所见。

以及 DAO 中的方法:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 /*#pageable*/ ORDER BY LASTNAME",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
 }
Run Code Online (Sandbox Code Playgroud)


Uda*_*tne 5

我可以成功地将分页集成到

\n
\n

spring-data-jpa-2.1.6

\n
\n

如下。

\n
@Query(\n value = \xe2\x80\x9cSELECT * FROM Users\xe2\x80\x9d, \n countQuery = \xe2\x80\x9cSELECT count(*) FROM Users\xe2\x80\x9d, \n nativeQuery = true)\nPage<User> findAllUsersWithPagination(Pageable pageable);\n
Run Code Online (Sandbox Code Playgroud)\n