带分页的Spring数据和本机查询


86

在一个网络项目中,将最新的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);
}

出于好奇,在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);
   }
}

我的查询中包含一个Pageable参数,所以hasPagingOrSortingParametertrue的,但它也在寻找#pageable#sort序列里面queryString,我不提供。

我尝试#pageable在查询末尾添加(这是一条注释),这使验证通过,但随后执行失败,表示查询需要一个附加参数:3而不是2。

有趣的是,如果我在运行时手动containsPageableOrSortInQueryExpression从更改falsetrue,则查询工作正常,因此我不知道为什么要检查该字符串是否在我自己的位置,queryString而且我也不知道如何提供它。

任何帮助将非常感激。

更新2018 年1月30日似乎spring-data项目的开发人员正在通过Jens SchauderPR来解决此问题。


不,我还没有找到解决方案。我在Spring JIRA中创建了票证,但没有响应:jira.spring.io/browse/DATAJPA-928。最后,我不需要分页,所以我没有试图做任何进一步的研究,或者尝试加倍努力。
Lasneyx

3
好的谢谢。作为解决方法,您可以添加“ \ n#pageable \ n”而不是“ #pageable”,但我希望以后会解决此问题。
Janar's

1
当前的修复使我的情况变得更糟。现在我的PageAble参数被完全忽略,查询不受限制地执行。因此,如果您插入了\ n#pageable \ n解决方法,请确保将其删除,否则会遇到麻烦。
鲁迪格·舒尔茨

Answers:


48

预先致歉,这几乎是对原始问题和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);

需要使用countQuery(在代码块中注释掉)Page<Author> 作为查询的返回类型,需要使用“ #pageable”注释周围的换行符来避免预期参数数量上的运行时错误(解决方法)。我希望这个错误会尽快修复...


1
就我而言,?#{#pageable}它正在工作\n#pageable\n
德米特里·斯托尔博夫'16

6
这有效。对于参数,您仍然可以使用命名参数。例子:authorId。我将您\n#pageable\n更改--#pageable\n为Postgresql。正如您所建议的那样,由于许多示例都使用List <>而不是Page <>,因此需要countQuery,您的答案就此出现了。我经历了相同的文档,如果不是您的答案,我将放弃。
Abhishek Dujari

2
如果您不编写countQuery并让框架处理该问题,那么有时您将无法通过查询正确地为您编写计数,并且您可能会看到一个错误的无效字段列表。您始终可以通过将以下条目添加到属性文件logging.level.org.hibernate.SQL = DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder = TRACE中来分析SQL语句,分别通过查询添加计数将解决问题。这可能取决于您使用的框架版本和数据库。
纳拉卡

就我而言,仅/*:pageable*/适用于SQL Server,Hibernate 5.4.1.Final和Spring Boot 2.2.1)
marioosh

35

这是使用2.0.4之前的Spring Data JPA程序的黑客。

代码已与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);   
}

ORDER BY ?#{#pageable}是为PageablecountQuery是为Page<User>


1
我不知道。尝试1.启用SQL语句的日志记录-spring.jpa.show-sql=false在中设置application.properties;2.?#{#pageable}在您的nativeQuery中进行设置,并3.从日志中分析结果SQL。@Lasneyx针对Spring Data JPA的特殊性创建了DATAJPA-928问题。
德米特里·斯托博夫'17

12

仅作记录,使用H2作为测试数据库,并在运行时使用MySQL,此方法有效(示例是group中的最新对象):

@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);

Spring Data JPA 1.10.5,H2 1.4.194,MySQL社区服务器5.7.11-log(innodb_version 5.7.11)。


适用于PostgreSQL。谢谢!
Maksym Chernikov

如果我们必须通过asc或desc动态将订单传递给查询该怎么办?
库尔伯山辛格

8

我有@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);

也为我使用DB2。
安德斯·梅尼克

@Query(nativeQuery = true,value =“从rqst中选择a。* a左外部联接table_b b a.id = b.id,其中a.code ='abc'ORDER BY-#pageable \ n”)不是工作:无法确定参数$ 2的数据类型
开发人员

7

尝试这个:

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);
}

"/* */"Oracle notation


某些原因导致可查询的分页查询后产生逗号,例如“ ORDER BY / *#pageable * /”,导致语法错误
d-man

我通过删除订单但生成了意外的异常字符:'#'
hicham abdedaime

5

我使用的是oracle数据库,但没有得到结果,而是d-man所说的生成逗号错误。

然后我的解决方案是:

Pageable pageable = new PageRequest(current, rowCount);

如您所见,创建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);
 }

1

以下两种方法都可以与MySQL配合使用,以对本机查询进行分页。但是,它们不适用于H2。它将抱怨sql语法错误。

  • ORDER BY?#{#pageable}
  • 通过a.id订购\ n#pageable \ n


1

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

弹簧数据jpa-2.1.6

如下。

@Query(
 value = “SELECT * FROM Users”, 
 countQuery = “SELECT count(*) FROM Users”, 
 nativeQuery = true)
Page<User> findAllUsersWithPagination(Pageable pageable);

0

它的工作原理如下:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = "select * from (select (@rowid\\:=@rowid+1) as RN, u.* from USERS u, (SELECT @rowid\\:=0) as init where  LASTNAME = ?1) as total"+
        "where RN between ?#{#pageable.offset-1} and ?#{#pageable.offset + #pageable.pageSize}",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
    Page<User> findByLastname(String lastname, Pageable pageable);
}

0

下面对我来说在MS SQL中工作

 @Query(value="SELECT * FROM ABC r where r.type in :type  ORDER BY RAND() \n-- #pageable\n ",nativeQuery = true)
List<ABC> findByBinUseFAndRgtnType(@Param("type") List<Byte>type,Pageable pageable);

0

我正在使用下面的代码。加工

@Query(value = "select * from user usr" +
  "left join apl apl on usr.user_id = apl.id" +
  "left join lang on lang.role_id = usr.role_id" +
  "where apl.scr_name like %:scrname% and apl.uname like %:uname and usr.role_id in :roleIds ORDER BY ?#{#pageable}",
  countQuery = "select count(*) from user usr" +
      "left join apl apl on usr.user_id = apl.id" +
      "left join lang on lang.role_id = usr.role_id" +
      "where apl.scr_name like %:scrname% and apl.uname like %:uname and usr.role_id in :roleIds",
  nativeQuery = true)
Page<AplUserEntity> searchUser(@Param("scrname") String scrname,@Param("uname") String  uname,@Param("roleIds") List<Long> roleIds,Pageable pageable);

1
请您解释一下为什么这个答案比已经存在数年的其他答案要好吗?
Dragonthoughts

0

从查询和计数查询中删除\ n#pageable \ n对我来说很有效。Springboot版本:2.1.5.RELEASE DB:Mysql


0

这在Groovy中为我工作(我正在使用Postgres):

@RestResource(path="namespaceAndNameAndRawStateContainsMostRecentVersion", rel="namespaceAndNameAndRawStateContainsMostRecentVersion")
    @Query(nativeQuery=true,
            countQuery="""
            SELECT COUNT(1) 
            FROM 
            (
                SELECT
                ROW_NUMBER() OVER (
                    PARTITION BY name, provider_id, state
                    ORDER BY version DESC) version_partition,
                *
                FROM mydb.mytable
                WHERE
                (name ILIKE ('%' || :name || '%') OR (:name = '')) AND
                (namespace ILIKE ('%' || :namespace || '%') OR (:namespace = '')) AND
                (state = :state OR (:state = ''))
            ) t
            WHERE version_partition = 1
            """,
            value="""
            SELECT id, version, state, name, internal_name, namespace, provider_id, config, create_date, update_date 
            FROM 
            (
                SELECT 
                ROW_NUMBER() OVER (
                    PARTITION BY name, provider_id, state
                    ORDER BY version DESC) version_partition,
                *
                FROM mydb.mytable
                WHERE 
                (name ILIKE ('%' || :name || '%') OR (:name = '')) AND
                (namespace ILIKE ('%' || :namespace || '%') OR (:namespace = '')) AND
                (state = :state OR (:state = ''))       
            ) t            
            WHERE version_partition = 1             
            /*#{#pageable}*/
            """)
    public Page<Entity> findByNamespaceContainsAndNameContainsAndRawStateContainsMostRecentVersion(@Param("namespace")String namespace, @Param("name")String name, @Param("state")String state, Pageable pageable)

这里的关键是使用: /*#{#pageable}*/

它允许我进行排序和分页。您可以使用类似以下内容的方法对其进行测试:http:// localhost:8080 / api / v1 / entities / search / namespaceAndNameAndRawStateContainsMostRecentVersion?namespace =&name =&state = published&page = 0&size = 3&sort = name,desc

当心这个问题:Spring Pageable不会翻译@Column名称


0

您可以将以下代码用于h2和MySQl

    @Query(value = "SELECT req.CREATED_AT createdAt, req.CREATED_BY createdBy,req.APP_ID appId,req.NOTE_ID noteId,req.MODEL model FROM SUMBITED_REQUESTS  req inner join NOTE note where req.NOTE_ID=note.ID and note.CREATED_BY= :userId "
        ,
         countQuery = "SELECT count(*) FROM SUMBITED_REQUESTS req inner join NOTE note WHERE req.NOTE_ID=note.ID and note.CREATED_BY=:userId",
        nativeQuery = true)
Page<UserRequestsDataMapper> getAllRequestForCreator(@Param("userId") String userId,Pageable pageable);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.