웹/Spring Data

[스프링 데이터 JPA] 2. 쿼리 메소드 기능

두잇베스트 2020. 12. 16. 16:42

2. 쿼리 메소드 기능

  • 메소드 이름으로 쿼리 생성
  • NamedQuery
  • @Query
  • 파라미터 바인딩
  • 반환 타입
  • 페이징과 정렬
  • 벌크성 수정 쿼리
  • @EntityGraph

 

쿼리 메소드 기능

  • 메소드 이름으로 쿼리 생성
  • @Query어노테이션을 사용해서 리포지토리 인터페이스 쿼리 직접 정의

 

메소드 이름으로 쿼리 생성

  • 메소드 이름을 분석해서 JPQL 쿼리 실행
public interface MemberRepository extends JpaRepository<Member, Long> {

    List<Member> findByUsername(String username);
    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
    List<Member> findTop3By();
}

메소드 이름으로 쿼리 생성 기능은 필드명이 변경하게 되면, 필히 메소드 이름도 함께 변경해야 한다.! 그렇지 않으면 애플리케이션 실행 시점에 오류가 발생한다.

더 자세한 문법은Spring Data JPA - Reference Documentation

 

@Query, 리포지토리 메소드에 쿼리 생성

@Query("select m from Member m where m.username = :username and m.age = :age") 
List<Member> findUser(@Param("username") String username, @Param("age") int age);

@Query("select m.username from Member m")
List<String> findUsernameList();
  • 실행할 메소드에 정적 쿼리를 작성하기 때문에 이름없는 메소드 쿼리라 할 수 있다.
  • 그래서 NamedQuery처럼 애플리케이션 실행시점에서 문법 오류를 발견할 수 있다는 장점이 있다.!

 

@Query, Dto 조회

public interface MemberRepository extends JpaRepository<Member, Long> {

@Query("select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join m.team t")
List<MemberDto> findMemberDto();

}

DTO로 직접 조회 하려면 new 명령어를 사용해야 한다.

 

MemberDto


package study.datajpa.dto;

import lombok.Data;
import study.datajpa.entity.Member;

@Data
public class MemberDto {

    private Long id;
    private String username;
    private String teamName;


    public MemberDto(Long id, String username, String teamName) {
        this.id = id;
        this.username = username;
        this.teamName = teamName;
    }
}


 

파라미터 바인딩

  • 위치 기반
  • 이름 기반

이름 기반 파라미터 바인딩은 위의 @Query에서 보여준 것처럼 이름으로 바인딩한것이다. 가독성과 유지보수를 위해 이름 기반 파라미터 바인딩을 사용해야한다. Collection 파라미터 바인딩

  • in 절 이용

@Query("select m from Member m where m.username in :names")
List<Member> findByNames(@Param("names") String names);

 

반환 타입

스프링 데이터 JPA는 유연한 반환 타입을 지원한다.

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

 

조회 결과가 없으면?

  • 단건 조회
    • 결과 없으면 null 반환
    • 결과가 2건 이상이면 : 예외 발생 ( javax.persistence.NonUniqueResultException)
  • 컬렉션 조회
    • 결과 없으면 [] 빈 컬렉션 반환

단건 조회를 한다면 스프링 데이터 JPA는 내부에서 JPQL의 getSingleResult() 호출한다. 그래서 결과가 2건이상 했을시 위의 예외가 발생한다. 사실 단건 조회에서 null을 반환하는 것도 예외가 발생하긴 한다. JPA에서는 결과가 없으면 javax.persistence.NoResultException 발생하지만 스프링 데이터 JPA는 이를 try..catch로 감싸서 null 로 반환한다.

 

 

결론
단건 조회에서 데이터에 null이 있을 수도 있고 없을수도 있으면 Optional 쓰는게 가장 좋다.

 

 

 

 

Reference

인프런 - 실전! 스프링 데이터 JPA