페이지 매김을 사용한 스프링 데이터 및 네이티브 쿼리


86

웹 프로젝트에서 MySQL 5.6 데이터베이스와 함께 최신 스프링 데이터 (1.10.2)를 사용하여 페이지 매김과 함께 네이티브 쿼리를 사용하려고하지만 org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException시작할 때 발생합니다.

업데이트 : 20180306이 문제는 이제 Spring 2.0.4 에서 수정되었습니다. 여전히 이전 버전에 관심이 있거나 이전 버전을 사용하는 경우 관련 답변과 주석에서 해결 방법을 확인하십시오.

Spring-data 문서에서 @Query 사용의 Example 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쿼리 끝에 (주석)을 추가하여 유효성 검사를 통과했지만 쿼리에 2 대신 3이라는 추가 매개 변수가 필요하다는 메시지가 실행에 실패합니다.

재미있는 점은 실행 중에 수동으로 containsPageableOrSortInQueryExpression에서 false로 변경 true하면 쿼리가 제대로 작동하므로 해당 문자열이 내 위치에 있는지 확인하는 이유를 queryString모르고 제공하는 방법을 모릅니다.

어떤 도움이라도 대단히 감사하겠습니다.

2018 년 1 월 30업데이트 Spring-Data 프로젝트의 개발자 가 Jens SchauderPR 을 통해이 문제에 대한 수정 작업을하고있는 것 같습니다.


아니요, 아직 해결책을 찾지 못했습니다. Spring JIRA에서 티켓을 만들었지 만 응답이 없습니다 : jira.spring.io/browse/DATAJPA-928 . 결국, 나는 페이지 매김이 필요하지 않았기 때문에 더 이상 조사하거나 그 티켓으로 더 열심히 밀려 고 시도하지 않았습니다.
Lasneyx

3
괜찮 감사. 해결 방법으로 "#pageable"대신 "\ n # pageable \ n"을 추가 할 수 있지만 나중에 수정되기를 바랍니다.
Janar

1
현재 수정으로 인해 상황이 더 나빠졌습니다. 이제 내 PageAble 매개 변수가 완전히 무시되고 쿼리가 무제한으로 실행됩니다. 따라서 \ n # pageable \ n 해결 방법을 삽입 한 경우 제거해야합니다. 그렇지 않으면 문제가 발생할 수 있습니다.
Rüdiger Schulz

답변:


48

미리 사과드립니다. 이것은 원래 질문과 Janar 의 의견을 거의 요약 한 것입니다 .

나는 같은 문제에 부딪혔다. 나는 SpringData의 Example 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.
Dmitry Stolbov

6
작동합니다. 인수의 경우 명명 된 매개 변수를 계속 사용할 수 있습니다. 예 :authorId. 나는 당신 \n#pageable\n--#pageable\npostgresql로 변경했습니다 . 많은 예제가 Page <> 대신 List <>를 사용하기 때문에 countQuery가 필요합니다. 나는 같은 문서를 봤고 당신의 대답이 아니었다면 그냥 포기했을 것입니다.
Abhishek Dujari

2
countQuery를 작성하지 않고 프레임 워크가이를 처리하도록하면 때때로 쿼리별로 개수를 올바르게 작성하지 못하여 잘못된 필드 목록으로 오류가 표시 될 수 있습니다. 아래 항목을 속성 파일 logging.level.org.hibernate.SQL = DEBUG에 추가하여 언제든지 SQL 문을 분석 할 수 있습니다. logging.level.org.hibernate.type.descriptor.sql.BasicBinder = TRACE 쿼리별로 개수를 별도로 추가하면 문제를 해결하십시오. 이는 사용중인 프레임 워크 버전 및 데이터베이스에 따라 달라질 수 있습니다.
Nalaka

제 경우에만 /*:pageable*/작동합니다 (SQL Server, Hibernate 5.4.1.Final 및 Spring Boot 2.2.1 사용)
marioosh

35

이것은 버전 2.0.4 이전의 SpringData 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}입니다 Pageable. countQuery입니다 Page<User>.


1
지금은 아니에요. 시도 1. SQL 문 로깅 활성화-set spring.jpa.show-sql=falsein application.properties; 2. ?#{#pageable}nativeQuery에서 설정 하고 3. 로그에서 결과 SQL을 분석합니다. @Lasneyx는 SpringData JPA의 이러한 특성에 대해 DATAJPA-928 문제를 만들었습니다 .
Dmitry Stolbov

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

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


PostgreSQL에서 일했습니다. 감사합니다!
Maksym Chernikov 2017

asc 또는 desc에 의한 순서를 쿼리에 동적으로 전달해야한다면 어떨까요?
Kulbhushan Singh

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에서도 나를 위해 일했습니다.
Anders Metnik 2017 년

@Query (nativeQuery = true, value = "select a. * from rqst a LEFT OUTER JOIN table_b b ON a.id = b.id where a.code = 'abc'ORDER BY-# pageable \ n") is not 작업 : 매개 변수 $ 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 * /"과 같은 "ORDER BY / * # pageable * /"과 같이 페이징 후 쉼표가있는 쿼리를 생성하여 구문 오류를 일으 킵니다
d-man

나는 주문을 제거했지만 예상치 못한 예외 문자를 생성했습니다 : '#'
hicham abdedaime

5

나는 오라클 데이터베이스를 사용하고 결과를 얻지 못했지만 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

MS SQL SERVER에서 "ORDER BY id \ n # pageable \ n"대신 "ORDER BY id DESC \ n-- #pageable \ n"을 사용했습니다.


1

페이지 네이션을 성공적으로 통합 할 수있었습니다.

spring-data-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 2010 년

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

-1

/ #pageable /을? # {# pageable}로 바꾸면 페이지 매김을 할 수 있습니다. PageableDefault를 추가하면 페이지 요소의 크기를 설정할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.