💡 쿼리 메소드 기능 3가지
- ⭐
메소드 이름
으로 쿼리 생성
JpaRepository extends한 인터페이스에 규칙에 맞게 메소드 이름 지으면 쿼리 알아서 생성해줌
@NamedQuery
Entity 위에 @NamedQuery로 JPQL 미리 작성 + 레포지토리에서 @NamedQuery 사용
- ⭐
@Query
@Query 사용해서 레포지토리 인터페이스에 쿼리 직접 정의✨ 메소드 이름으로 쿼리 생성과 @Query를 주로 사용한다!
public interface MemberRepository extends JpaRepository<Member, Long>{
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
// 파라미터명 정확히 작성해야함!
// ERROR : findByUsername2AndAgeGreaterThan
List<Member> findTop3By();
}
🚨주의!🚨
- 메소드 이름은 관례를 따라야 한다.
- 파라미터명 정확히 작성해야한다.
자세한 메소드 이름 기준은 공식문서 참고!
(CH5.1.3 Query Methods - Query Creation 부분)
🚨주의!🚨
엔티티에 작성한 필드명을 변경
했을 때, Repository에 작성한메소드 안의 필드명도 변경
해야함!!
조회 : find...By
, read...By
, query...By
, get...By
✅ 참고
...
에는findHelloBy
처럼 설명이 들어가도 됨 ->쿼리에 영향 X
COUNT : count...By
EXISTS : exists...By
삭제 : delete...By
DISTINCT : findDistinct
, findMemberDistinctBy
LIMIT : findFirst3
, findFirst
, findTop
, findTop3
쿼리에 이름을 부여하고 호출하는 기능
작성 방법
@NamedQuery( name = "NamedQuery명", query = "jpql 작성" )
NamedQuery 이름 관례 :
엔티티명.함수명
@NamedQuery( // Named Query 큰 장점: 정적 쿼리라서 애플리케이션 로딩 시점에 쿼리 파싱해 문법 오류 발견시 에러 발생
name = "Member.findByUsername", // 관례: 엔티티명.함수명
query = "select m from Member m where m.username = :username" // jpql 작성
)
public class Member{
...
}
em.createNamedQuery(@NamedQuery의 name, 엔티티.class)
@Repository
public class MemberJpaRepository {
@PersistenceContext
private EntityManager em;
// Named Query 사용
public List<Member> findByUsername(String username){
return em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", username)
.getResultList();
}
}
하지만, 구현하는 것이 너무 귀찮다! -> 더 편리한 방법 Spring Data JPA가 제공
@Query(name = "@NamedQuery의 name")
public interface MemberRepository extends JpaRepository<Member, Long>{
// Named Query
@Query(name = "Member.findByUsername") // NamedQuery의 name
List<Member> findByUsername(@Param("username") String username);// @Param : JPQL parameter setting
// 단, @Query줄 주석처리해도 정상 실행됨.
// Member.findByUsername(엔티티.함수명)을 이용해서 NamedQuery에서 이러한 이름의 NamedQuery있는지 먼저 확인함.
// 해당 이름의 NamedQuery 발견하면 NamedQuery 실행하고, 없으면 쿼리 이름으로 쿼리 생성하는 방식 사용
// 즉, 우선 순위가 NamedQuery > 쿼리 이름으로 쿼리 생성
}
참고
@Query(name = "Member.findByUsername")
@Query를 작성안해도 정상적으로 실행됨!!
아래와 같이 @Query를 적지 않았을 때,List<Member> findByUsername(@Param("username") String username);
동작 과정
1. 반환타입.함수명(Member.findByUsername
)이라는 name을 가진@NamedQuery가 해당 Entity에 선언
되어있는지 확인
2. 선언되어있지 않다면쿼리 이름으로 쿼리 생성[1번 방법]
그냥 JPQL과 달리, 문법 오류 발생시 애플리케이션 시작 시점에 에러가 발생한다.
public List<Member> findByUsernameAndAgeGreaterThan(String username, int age){
return em.createQuery("select m from Member m where m.usern2222ame = :username and m.age > :age")
.setParameter("username", username)
.setParameter("age", age)
.getResultList();
}
createQuery의 첫번째 parameter가 그냥 String이라서 오타가 발생해도 정상적으로 애플리케이션 작동
BUT, 고객이 이 함수 관련된 것을 누르는 순간 오류 터짐
@NamedQuery(
name = "Member.findByUsername", // 관례: 엔티티명.함수명
query = "select m from Member m where m.uswerwerwre222ername = :username"
)
public class Member {
...
}
NamedQuery는 오타내면 애플리케이션 시작 시점에 에러 터짐
Named Query는 기본적으로 정적 쿼리
라서 애플리케이션 로딩 시점에 쿼리를 파싱
할 수 있다.
그래서 JPQL을 SQL로 미리 만들어
둘 수 있고, 이 과정에서 개발자에게는 애플리케이션 로딩 시점에 오류를 잡을 수
있도록 알려줄 수 있다.
public interface MemberRepository extends JpaRepository<Member, Long>{
// @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);
}
😢 메소드이름으로 쿼리 생성[1번 방법] 단점
- 파라미터가 많아질수록 함수명이 길어짐
😄 @Query 사용[3번방법] 장점
- 쿼리를 repository interface의 함수 위에 바로 정의 가능.
- 파라미터가 많아지더라도 함수명 간략하게 적을 수 있음.
- 문법 오류가 있는 JPQL을 @Query에 작성했을 때, 애플리케이션 로딩 시점에 오류를 잡아냄.
🟢 간단 -
메소드 이름으로 쿼리 생성[1번 방법]
🔴 복잡 -@Query[3번 방법]
사용해 Repository Interface에 쿼리 직접 정의 +메소드 이름은 간단하게
작성
🟡 동적 쿼리 -QueryDSL
사용