Spring + Boot

JPA 페이징 / 정렬 처리하기

devRachel 2021. 4. 8. 18:04

오라클에서는 인라인뷰를, MySQL에서는 limit을 사용하여 페이징 처리를 했지만 JPA는 Dialect를 이용해서 처리합니다.

JPA가 실제 데이터베이스에서 사용하는 SQL의 처리를 자동으로 하기 때문에 개발자들은 SQL이 아닌 API의 객체와 메서드를 사용하는 방식으로 페이징 처리를 할 수 있게 되었습니다.

 

페이징처리와 정렬은 findAll() 이라는 메서드를 사용합니다. JpaRepository 인터페이스의 상위인 PagingAndSortRepository의 메서드로 파라미터로 전달되는 Pageable이라는 타입의 객체에 의해 실행되는 쿼리를 결정하게 됩니다. 리턴 타입을 Page<T>로 지정했을 경우 반드시 파라미터를 Pageable타입을 사용해야 합니다.

 

페이지 처리를 위해 가장 중요한 것은 org.springframework.data.domain.Pagealbe 인터페이스입니다. Pageable 인터페이스는 페이지 처리에 필요한 정보를 전달하는 용도로 인터페이스이기에 실제 객체를 생성할 때는 구현체인 org.springframework.data.domain.PageRequest 클래스를 사용합니다.

 

PageRequest 클래스의 생성자는 protected로 선언돼있기 때문에 new를 사용할 수 없습니다. 객체를 생헝하기 위해서 static한 of()를 이용해서 처리합니다. PageRequest 생성자에는 page, size, Sort라는 정보를 이용해서 객체를 생성합니다.

 

static 메서드인 of()는 

of(int page, int size) : 0부터 시작하는 페이지 번호와 개수(size), 정렬이 지정되지 않음

of(int page, int size, Sort.Direction direction, String …props) : 0부터 시작하는 페이지 번호와 개수, 정렬의 방향과 정렬 기준 필드들

of(int page, int size, Sort sort) : 페이지 번호와 개수, 정렬 관련 정보

 

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
  
  @Test
    public void testPageDefalut(){
        //1페이지 10개
        Pageable pageable = PageRequest.of(0, 10);

        Page<Memo> result = memoRepository.findAll(pageable);

        System.out.println(result);
    }

 

 

 

실행 결과

 

Hibernate: 
    select
        memo0_.mno as mno1_0_,
        memo0_.memo_text as memo_tex2_0_ 
    from
        tbl_memo memo0_ limit ?
Hibernate: 
    select
        count(memo0_.mno) as col_0_0_ 
    from
        tbl_memo memo0_
Page 1 of 10 containing org.zerock.ex2.entity.Memo instances

 

 

Page 타입은 단순 해당 목록만으로 가져오는 것이 아니라 실제 페이지 처리에 필요한 전체 데이터의 개수를 가져오는 쿼리를 같이 처리합니다. 만일 데이터가 충분하지 않다면 데이터의 개수를 가져오는 쿼리를 실행하지 않습니다.

 

Page<엔티티 타입>은 쿼리 결과를 사용하기 위해 여러 메서드를 지원합니다. 

 

 @Test
    public void testPageDefalut(){
        //1페이지 10개
        Pageable pageable = PageRequest.of(0, 10);

        Page<Memo> result = memoRepository.findAll(pageable);

        System.out.println(result);

        System.out.println("______________________");
        System.out.println("총 페이지 수 : " + result.getTotalPages());
        System.out.println("전체 개수 : " +  result.getTotalElements());
        System.out.println("현재 페이지 번호 : " + result.getNumber());
        System.out.println("페이지당 데이터 개수 : " + result.getSize());
        System.out.println("다음 페이지가 존재 하는지 ??? : " + result.hasNext());
        System.out.println("시작 페이지가 있는지 ??? : " + result.isFirst());
    }

 

 

Hibernate: 
    select
        memo0_.mno as mno1_0_,
        memo0_.memo_text as memo_tex2_0_ 
    from
        tbl_memo memo0_ limit ?
Hibernate: 
    select
        count(memo0_.mno) as col_0_0_ 
    from
        tbl_memo memo0_
Page 1 of 10 containing org.zerock.ex2.entity.Memo instances
______________________
총 페이지 수 : 10
전체 개수 : 99
현재 페이지 번호 : 0
페이지당 데이터 개수 : 10
다음 페이지가 존재 하는지 ??? : true
시작 페이지가 있는지 ??? : true

 

getContent()를 이용해서 List<엔티티타입> 또는 Stream<엔티티 타입>을 반환하는 get()을 이용해서 데이터를 가져올 수 있습니다.

 

    for(Memo memo : result.getContent()){
            System.out.println(memo);
        }

 

Hibernate: 
    select
        memo0_.mno as mno1_0_,
        memo0_.memo_text as memo_tex2_0_ 
    from
        tbl_memo memo0_ limit ?
Hibernate: 
    select
        count(memo0_.mno) as col_0_0_ 
    from
        tbl_memo memo0_
Page 1 of 10 containing org.zerock.ex2.entity.Memo instances
______________________
총 페이지 수 : 10
전체 개수 : 99
현재 페이지 번호 : 0
페이지당 데이터 개수 : 10
다음 페이지가 존재 하는지 ??? : true
시작 페이지가 있는지 ??? : true
______________________
Memo(mno=1, memoText=테스트_____1)
Memo(mno=2, memoText=테스트_____2)
Memo(mno=3, memoText=테스트_____3)
Memo(mno=4, memoText=테스트_____4)
Memo(mno=5, memoText=테스트_____5)
Memo(mno=6, memoText=테스트_____6)
Memo(mno=7, memoText=테스트_____7)
Memo(mno=8, memoText=테스트_____8)
Memo(mno=9, memoText=테스트_____9)
Memo(mno=10, memoText=테스트_____10)

 

 

이제 정렬을 해보겠습니다. PageRequest에는 정렬과 관련된 org.springframework.data.domain.Sort타입을 파라미터로 전달할 수 있습니다. Sort는 한 개에서 여러 개의 필드값을 이용하여 순차적 정렬(asc)이나 역순 정렬(desc)를 지정할 수 있습니다. 

 

   @Test
    public void testSort(){
        Sort sort1 = Sort.by("mno").descending();
        Pageable pageable = PageRequest.of(0, 10, sort1);
        Page<Memo> result = memoRepository.findAll(pageable);

        result.get().forEach(memo -> {
            System.out.println(memo);
        });
    }

실행결과

 

Hibernate: 
    select
        memo0_.mno as mno1_0_,
        memo0_.memo_text as memo_tex2_0_ 
    from
        tbl_memo memo0_ 
    order by
        memo0_.mno desc limit ?
Hibernate: 
    select
        count(memo0_.mno) as col_0_0_ 
    from
        tbl_memo memo0_
Memo(mno=99, memoText=테스트_____99)
Memo(mno=98, memoText=테스트_____98)
Memo(mno=97, memoText=테스트_____97)
Memo(mno=96, memoText=테스트_____96)
Memo(mno=95, memoText=테스트_____95)
Memo(mno=94, memoText=테스트_____94)
Memo(mno=93, memoText=테스트_____93)
Memo(mno=92, memoText=테스트_____92)
Memo(mno=91, memoText=테스트_____91)
Memo(mno=90, memoText=테스트_____90)

정렬 조건은 Sort 객체의 and()를 이용해서 여러개의 정렬 조건을 다르게 지정할 수 있습니다.

@Test
    public void testSort(){
        Sort sort1 = Sort.by("mno").descending();
        Sort sort2 = Sort.by("memoText").ascending();
        Sort sortAll = sort1.and(sort2); //and를 이용한 연결
        Pageable pageable = PageRequest.of(0, 10, sortAll);
        Page<Memo> result = memoRepository.findAll(pageable);

        result.get().forEach(memo -> {
            System.out.println(memo);
        });
    }

 

 

Hibernate: 
    select
        memo0_.mno as mno1_0_,
        memo0_.memo_text as memo_tex2_0_ 
    from
        tbl_memo memo0_ 
    order by
        memo0_.mno desc,
        memo0_.memo_text asc limit ?
Hibernate: 
    select
        count(memo0_.mno) as col_0_0_ 
    from
        tbl_memo memo0_
Memo(mno=99, memoText=테스트_____99)
Memo(mno=98, memoText=테스트_____98)
Memo(mno=97, memoText=테스트_____97)
Memo(mno=96, memoText=테스트_____96)
Memo(mno=95, memoText=테스트_____95)
Memo(mno=94, memoText=테스트_____94)
Memo(mno=93, memoText=테스트_____93)
Memo(mno=92, memoText=테스트_____92)
Memo(mno=91, memoText=테스트_____91)
Memo(mno=90, memoText=테스트_____90)