티스토리 뷰

JPA Repository를 상속하면 다음과 같이 자유롭게 find...By 안에 어떤 이름이든 지을 수 있으며 BY 이후가 중요하다.

 

    List<Member> findListByUsername(String username); //컬렉션
    Member findMemberByUsername(String username); //단건
    Optional<Member> findOptionalByUsername(String username); //단건 Optional

 

 

주의점

- list로 받으면 절대 null이 아니다 size가 0으로 나온다. 그러므로 Null 체크 조심해야 한다.

- 단건 조회에서는 Member일 경우 null을 반환한다.

- 그러므로 자바8 이상에서 부터는 그냥 Optional로 받아서 처리해야한다.

 

 

 

순수 JPA 페이징

    public List<Member> findByPage(int age, int offset, int limit){
        return em.createQuery("select m from Member m where m.age = :age order by m.username desc")
                .setParameter("age",age)
                .setFirstResult(offset)
                .setMaxResults(limit).getResultList();
    }

    public Long totalCount(int age){
        return em.createQuery("select count(m) from Member m where m.age = :age", Long.class)
                .setParameter("age", age)
                .getSingleResult();
    }

 

    @Test
    public void paging() {
        memberJpaRepository.save(new Member("member1" , 10));
        memberJpaRepository.save(new Member("member2" , 10));
        memberJpaRepository.save(new Member("member3" , 10));
        memberJpaRepository.save(new Member("member4" , 10));
        memberJpaRepository.save(new Member("member5" , 10));
        
        int age = 10;
        int offset = 1;
        int limit = 3;

        List<Member> members = memberJpaRepository.findByPage(age, offset, limit);
        Long totalCount = memberJpaRepository.totalCount(age);

        Assertions.assertThat(members.size()).isEqualTo(3);
        Assertions.assertThat(totalCount).isEqualTo(5);
    }

 

이곳에 페이징 코드를 섞어서 진행 했을 것이다. data JPA에서는 사용법이 많이 개선 되었다.

 

data JPA 페이징과 정렬

 

    Page<Member> findByAge(int age, Pageable pageable);

 

 @Test
    public void paging() {
        memberRepository.save(new Member("member1" , 10));
        memberRepository.save(new Member("member2" , 10));
        memberRepository.save(new Member("member3" , 10));
        memberRepository.save(new Member("member4" , 10));
        memberRepository.save(new Member("member5" , 10));

        int age =10 ;
        PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));

        Page<Member> page = memberRepository.findByAge(age, pageRequest); //반환 타입을 Page로 받으면 totalCount 쿼리도 함께 날린다.

        List<Member> content = page.getContent();
        long totalElements = page.getTotalElements();

        for (Member member : content) {
            System.out.println("member = " + member);
        }
        System.out.println("totalElements = " + totalElements);

        Assertions.assertThat(content.size()).isEqualTo(3);
        Assertions.assertThat(page.getTotalElements()).isEqualTo(5); //총개수
        Assertions.assertThat(page.getNumber()).isEqualTo(0); //페이지 넘버도 가져올 수 있다....
        Assertions.assertThat(page.getTotalPages()).isEqualTo(2); // 총 페이지 갯수
        Assertions.assertThat(page.isFirst()).isTrue(); // 첫페이지인지
        Assertions.assertThat(page.hasNext()).isTrue(); // 다음페이지가 있는지

    }

 

Repository 메소드의 파라미터에 PageAble을 넣은 뒤에 

호출 시 PageRequest를 작성한다. pageNumber와 가져올갯수 + 필요하다면 정렬까지 넣는다.

 

호출만 했음에도 리턴 받은 객체는 다 정리해서 자동으로 페이징을 해준다.....

 

Slice

    Slice<Member> findByAge(int age, Pageable pageable);
   @Test
    public void paging() {
        memberRepository.save(new Member("member1" , 10));
        memberRepository.save(new Member("member2" , 10));
        memberRepository.save(new Member("member3" , 10));
        memberRepository.save(new Member("member4" , 10));
        memberRepository.save(new Member("member5" , 10));

        int age =10 ;
        PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));

        //Page<Member> page = memberRepository.findByAge(age, pageRequest); //반환 타입을 Page로 받으면 totalCount 쿼리도 함께 날린다.
        Slice<Member> page = memberRepository.findByAge(age, pageRequest); //리미트를 3으로 주지만 +1 개를 해서 가져온다. 더보기를 클릭할 때를 대비해서 만들어졌다. 또 그냥 List로 만들어도 된다.

        List<Member> content = page.getContent();

        for (Member member : content) {
            System.out.println("member = " + member);
        }

        Assertions.assertThat(content.size()).isEqualTo(3);
        Assertions.assertThat(page.getNumber()).isEqualTo(0); //페이지 넘버도 가져올 수 있다....
        Assertions.assertThat(page.isFirst()).isTrue(); // 첫페이지인지
        Assertions.assertThat(page.hasNext()).isTrue(); // 다음페이지가 있는지

    }

 

slice로 받을 수도 있는데, 리미트를 3으로 주어도 +1을 더 주는데 그 이유는 보통 더보기 버튼 같은 곳에 많이 사용하기 때문이다.

 

 

 

실무에서 적용이 필요한 부분

totalCount는 양에 따라서 성능에 저하가 올 수 있는 부분이다.

- 만약 team을 함께 불러오는 쿼리이리 경우 join으로 인해 카운트가 변할 수 있다. 그래서 카운트 쿼리는 분리해서 사용하기도 한다.

    @Query(value = "select m from Member m left join m.team",
            countQuery = "select count(m.username) from Member m")
    Page<Member> findByAge(int age, Pageable pageable);

 

 

실무꿀팁

Page는 그대로 반환하면 안된다. Dto로 반환해서 옮겨야 한다.

        Page<Member> page = memberRepository.findByAge(age, pageRequest); //반환 타입을 Page로 받으면 totalCount 쿼리도 함께 날린다.

        Page<MemberDto> toMap = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null)); //얘는 반환해도 된다.

아래 것은 옮겨도 된다.

 

 

주의점 : page index는 1이 아닌 0부터 시작한다.

'dev_공부일지 > spring data JPA' 카테고리의 다른 글

@EntityGraph  (0) 2024.03.06
벌크성 수정 쿼리  (0) 2024.03.05
@Query 값 DTO 조회하기 , 파라미터 바인딩  (0) 2024.03.05
JPA NamedQuery  (0) 2024.03.05
메소드 이름으로 쿼리 생성  (0) 2024.03.05
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함