5. 쿼리 메소드 기능

민정·2022년 12월 7일
0

Spring Data JPA

목록 보기
5/17
post-thumbnail

📌 미리 보기

💡 쿼리 메소드 기능 3가지

  1. 메소드 이름으로 쿼리 생성
    JpaRepository extends한 인터페이스에 규칙에 맞게 메소드 이름 지으면 쿼리 알아서 생성해줌

  2. @NamedQuery
    Entity 위에 @NamedQuery로 JPQL 미리 작성 + 레포지토리에서 @NamedQuery 사용

  3. @Query
    @Query 사용해서 레포지토리 인터페이스에 쿼리 직접 정의

✨ 메소드 이름으로 쿼리 생성과 @Query를 주로 사용한다!


1. 메소드 이름으로 쿼리 생성

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

😢 BAD

  • 파라미터 많아지면, 함수명이 길어짐.
  • 파라미터 2개 이하까지 사용 추천

😄 GOOD

  • 짧은 쿼리, 간단한 쿼리 작성할 때 많이 사용
  • 잘못된 메소드명 작성해도 애플리케이션 로딩 시점에 에러 발생


2. 메소드 이름으로 JPA NamedQuery 호출

쿼리에 이름을 부여하고 호출하는 기능

엔티티에 @NameQuery 작성

작성 방법

@NamedQuery(
	name = "NamedQuery명",
    query = "jpql 작성"
)

NamedQuery 이름 관례 : 엔티티명.함수명

⭐ Member Class

@NamedQuery( // Named Query 큰 장점: 정적 쿼리라서 애플리케이션 로딩 시점에 쿼리 파싱해 문법 오류 발견시 에러 발생
        name = "Member.findByUsername", // 관례: 엔티티명.함수명
        query = "select m from Member m where m.username = :username" // jpql 작성
)
public class Member{
	...
}

@NamedQuery 사용

1) 순수 JPA

em.createNamedQuery(@NamedQuery의 name, 엔티티.class)

📁 MemberJpaRepository

@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가 제공


2) Spring Data JPA

📁 MemberRepository

@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번 방법]


❌ @NamedQuery 실무에서 사용 거의 X

  • 엔티티 위에 @NamedQuery가 작성되어있는 것 별로
  • Spring Data JPA가 제공하는 기능인 Repository Interface에서 메서드에 바로 쿼리를 지정하는 방법이 너무 편리!(3번 방법)

😄 NamedQuery의 큰 장점

그냥 JPQL과 달리, 문법 오류 발생시 애플리케이션 시작 시점에 에러가 발생한다.

✏️ JQPL

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

@NamedQuery(
        name = "Member.findByUsername", // 관례: 엔티티명.함수명
        query = "select m from Member m where m.uswerwerwre222ername = :username"
)
public class Member {
	...
}

NamedQuery는 오타내면 애플리케이션 시작 시점에 에러 터짐

Named Query는 기본적으로 정적 쿼리라서 애플리케이션 로딩 시점에 쿼리를 파싱할 수 있다.
그래서 JPQL을 SQL로 미리 만들어둘 수 있고, 이 과정에서 개발자에게는 애플리케이션 로딩 시점에 오류를 잡을 수 있도록 알려줄 수 있다.


3. @Query 사용해 Repository Interface에 쿼리 직접 정의

📁 MemberRepository

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 사용



출처

김영한 강사님 - 인프런 실전! 스프링 데이터 JPA

0개의 댓글