쿼리 메서드의 3가지 기능
메서드 이름으로 쿼리 생성
메서드 이름으로 JPA NamedQuery 호출
@Query 어노테이션을 사용해 리포지토리 인터페이스에 쿼리 직접 정의
특징
JpaRepository 를 상속한 인터페이스에서 메서드 이름만 정의하면 알아서 메서드를 구현하여 사용할 수 있게 하는 기능
다양한 조건을 지정하여 쿼리를 이름으로 짤 수 있게 해줌
어떤 이름을 설정해야 원하는 쿼리를 만들 수 있는지는 공식 문서를 참고하자. (https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html)
단점: 조건이 많아지면 메서드명이 너무 길어짐
주요 기능
조회: find...By, read...By, query...By, get...By
COUNT: count...By 반환 타입 long
EXISTS: exists...By 반환 타입 boolean
삭제: delete...By, remove...By 반환 타입 long
DISTINCT: findDistinct, findMemberDistinctBy
LIMIT: finrFirst3, findFirst, finrTop, finrTop3
특징
@NamedQuery 어노테이션을 사용해 엔티티에 정의하거나, xml 파일에 정의한 NamedQuery를 쉽게 사용할 수 있도록 돕는 기능
@Query 어노테이션에 name 속성 값으로 정의한 쿼리의 이름을 넣으면 내부 구현체를 Data JPA 가 생성
NamedQuery 에 파라미터가 존재할 경우 @Param 어노테이션을 통해 메서드 인자에 파라미터명을 명시해야함
NamedQuery 의 이름을 '엔티티명.메서드명' 으로 지정할 경우 @Query 어노테이션을 통해 명시해주지 않아도 알아서 NamedQuery 를 활용해 구현체를 만들어준다. (메서드 이름보다 우선순위로 구현, 기본값)
장점
애플리케이션 로딩 시점에 쿼리에 잘못된 부분이 있는지 파싱하여 오류를 띄워줌
메서드 이름을 마음대로 정의할 수 있음
한계: 쿼리를 엔티티에 적거나, xml 파일에 두어야하기에 메서드에 바로 쿼리를 적을 수 있는 3번 기능에 의해 실무에선 잘 쓰이지 않음
특징
@Query 어노테이션을 통해 메서드에 바로 JPQL 을 작성할 수 있음
@Param 어노테이션을 통해 JPQL에 쓰일 파라미터명과 인자를 매핑
엔티티 조회 뿐만 아니라 DTO로 조회, 단순 값 조회 등도 가능
장점
NamedQuery 와 마찬가지로 애플리케이션 로딩 시점에 쿼리를 파싱하여 에러를 발생시키며, 메서드 이름을 마음대로 정의할 수 있음
리포지토리에 바로 JPQL을 작성할 수 있어 가독성이 좋음
파라미터 바인딩
JPQL의 파라미터 바인딩 방법에는 순서 기반 방법과 이름 기반 방법이 있다.
순서 기반 방법: 파라미터 자리에 ?1, ?2 등 순서 기반으로 파라미터를 넣는 방법, 유지보수에 힘들며 가독성도 좋지 않아 잘 사용하지 않음
이름 기반 방법: 파라미터 자리에 :name, :age 등 이름을 기반으로 파라미터를 넣는 방법, 위 방법의 안좋은 점을 모두 보완
JPQL 에서는 SQL 에서 다루기 까다로운 Collection 파라미터도 쉽게 다룰 수 있다.
예시)
@Query("select m from Member m where m.username in :names")
List<Member> findMembersByUsernames(@Param("names") List<String> names);
스프링 데이터 JPA 의 다양한 반환타입
데이터 JPA 는 반환 타입에 맞추어 구현을 해주는 기능이 존재한다.
예시)
List<Member> findMembersByUsername(String username);
Member findMemberByUsername(String username);
Optional<Member> findOptionalMemberByUsername(String username);
이 외에도 비동기 처리를 할 수 있는 Future 반환 타입이나, 페이징을 위한 Page 반환 타입등 많은 타입이 존재한다.
반환 타입에 따른 주의점
Optional타입과 컬렉션 타입을 반환 타입으로 사용할 경우 값이 존재하지 않아도 문제가 되지 않지만, 일반 클래스 타입은 null이 반환된다. (JPA 에서는 에러를 반환하지만, 데이터 JPA 가 에러를 없애고 null 값을 반환함)
Optional, 일반 클래스 타입을 반환 타입으로 사용할 경우 반환 값이 두 개 이상이라면, IncorrectResultSizeDataAccessException 에러가 발생한다.