Query 부터 페이징까지

JIWOO YUN·2023년 10월 16일
0

SpringDataJPA

목록 보기
2/4
post-custom-banner

Query를 통해서 값 or DTO 조회하기

값 가져오기

@Query("select m.username from Member m")
List<String> findUsername();

DTO로 직접 조회하기

  • DTO 조회시 new 를 꼭 적어줘야하고 생성자로 new 하듯이 적어줘야함. -> JPQL에서 제공하는 문법
    @Query("select new study.data_jpa.dto.MemberDto(m.id,m.username,t.name) " +
            "from Member m join m.team t")
    List<MemberDto> findMemberDto();

반환타입

  • JPA는 유연한 반환타입을 제공함.

List -> 컬렉션

단건-> optional도 가능하고 반환타입으로 가능.

컬렉션으로 조회 결과가 없는 경우 -> 빈 컬렉션을 반환한다.

단건 조회에서 결과가 없는 경우 -> null 반환 , 2개이상인경우 -> NonUniqueException 반환.

  • 순수 JPA 로 할 경우 -> getResultList() 메서드를 호출해서 결과가 없은 noResultException 예외를 터뜨림 -> 이러면 개발자는 try-catch문으로 감싸줘야함.
  • 하지만 스프링데이터 JPA는 알아서 try-catch문으로 감싸고 없는 경우 null을 반환해주기 때문에 결과가 없을 때 exception을 터뜨리지 않아서 좋음.

자바 8이 나온 후부터는 Optional을 통해서 반환을 받는다. -> 결과가 있을수도 있고 없을 수도 있는 경우 일단 진행됨.


JPA 와 스프링 데이터 JPA의 차이점

둘에 대해서 알지 못한듯해서 정리.

  • JPA 는 객체 - 관계 매핑을 위한 표준 명세 인터페이스
    • 자바 애플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스와 어노테이션의 표준 집합이다.
  • 스프링 데이터 JPA는 JPA 기반 애플리케이션 개발을 보다 간편하게 만드는 프레임워크이다.
    • JPA위에 추가적인 기능을 제공 -> 개발을 간편하게 만들어줌.

순수 JPA 페이징과 정렬

SQL로 페이징 정렬을 하는 것은 꽤 어려운편.

-> 순수 JPA의 경우 SQL로 받은다음 setFirstResult를 통해서 몇번째 부터 페이징할건지 정하고

setMaxResult를 통해서 최대 몇개를 가져올건지를 정할수있게됨.

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

스프링 데이터 JPA 페이징

  • Sort와 Pageable 두개로 다 처리시켜버린다.

PageRequest를 통해서 repository에 Paging을 요청할 때 사용함.

PageRequest.of(페이지번호,페이지크기,Sort.by(Sort.Direction.DESC, "username")); 

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

 Page<Member> page = memberRepository.findByAge(age,pageRequest);

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

//이게 TotalCount
long totalElements = page.getTotalElements();

반환타입을 Page로 할 경우 totalCount Query까지 다 날려줌. -> 따로 구할 필요없음.

테스트를 통해서 실험을해보니 count를 나는 날리지 않았는데 page반환을 받다보니까 알아서 count query가 나가는 모습이다.

Page를 Slice로 바꾸는 경우 PageRequest에서 size에 +1 만큼 가져옴 -> totalCount 같은걸 제공하지 않는다.

-> Slice가 Page보다 상위기 때문에 실수로 반환타입을 Slice로 하고 가져오는걸 Page로 한다해도 돌아가기 때문에 조심해야함.

Count Query를 분리 가능

@Query(value = "select m from Member m",
 countQuery = "select count(m.username) from Member m")
Page<Member> findMemberAllCountBy(Pageable pageable);

복잡해지면 성능을 비교하고 분리를 진행해야함. -> 성능차이가없을때는 굳이 안해도됨.

PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));

-> 여기서 Sorting 조건이 복잡해지면 안풀리는 경우가 존재하기 때문에 -> 이러한 문제가 생기는 경우 따로 보내는게 맞다.

실무 꿀팁

  • API에 직접 반환을 하면 Entity노출이 생기기 때문에 DTO로 변환해서 넘겨야한다.

DTO로 변환하는 법

page.map(member -> new MemberDto(member.getId(),member.getUsername(),null));

page를 맵핑을 통해서 DTO로 손쉽게 반환이 가능하다.


profile
열심히하자
post-custom-banner

0개의 댓글