자바생
article thumbnail
728x90

쿼리 메서드란

  • repository interface에 선언되는 DB에서 정보를 찾는 메서드

 

spring data JPA가 제공하는 쿼리 메서드 기능

  • 메서드 이름으로 쿼리 생성
  • 메서드 이름으로 JPA NamedQuery 호출
  • @Query 어노테이션을 사용하여 repository interface에 쿼리 직접 정의

 

메서드 이름으로 쿼리 생성

  • spring data jpa를 사용하지 않는다면 작성해야할 JPQL
public List<Member> findByUsernameAndAge(String username, int age) {
    return em.createQuery(
            "select m from Member m" +
                    " where m.username = :username" +
                    " and m.age = :age", Member.class)
            .setParameter("age", age)
            .setParameter("username", username)
            .getResultList();
}
@Test
void findByUsernameAndAge() throws Exception {
    //given
    Member m1 = new Member("AAA", 10);
    Member m2 = new Member("AAA", 20);

    memberJpaRepository.save(m1);
    memberJpaRepository.save(m2);

    //when
    List<Member> result = memberJpaRepository.findByUsernameAndAge("AAA", 10);

    //then
    assertThat(result.get(0)).isEqualTo(m1);
}

  • 위 코드를 작성하면 사진과 같은 쿼리가 나가게 된다(당연한 결과)
  • 하지만 여기서 spring data jpa가 제공하는 "메서드 이름으로 쿼리 생성"을 사용해보자
List<Member> findByUsernameAndAge(String username, int age);

 

만약에 메서드 이름을 규칙에 따라 작성하지 않는다면?

List<Member> findByUsernameasdAndAge(String username, int age);

  • 애플리케이션을 실행하면 위와 같은 에러가 발생한다
  • 질문 : spring data jpa가 어떻게 알고 쿼리를 자동으로 작성해줄까?

 

그 외 다른 쿼리 메서드

List<Member> findTop3By();

select member0_.member_id as member_i1_0_, 
member0_.age as age2_0_, 
member0_.team_id as team_id4_0_, 
member0_.username as username3_0_ 
from member member0_ limit 3;
  • 해당 기능은 엔티티의 필드명이 변경되면 메서드 이름도 "함께 변경"해야한다

 

JPA NamedQuery

@NamedQuery(
        name="Member.findByUsername",
        query="select m from Member m where m.username = :username"
)
public class Member {}
  • JPA를 직접 사용하여 Named 쿼리를 호출
public List<Member> findByUsername(String username) {
    return em.createNamedQuery("Member.findByUsername", Member.class)
            .setParameter("username", username)
            .getResultList();
}
  • spring data jpa를 사용하여 Named 쿼리 호출
public interface MemberRepository extends JpaRepository<Member, Long>{
    @Query(name = "Member.findByUsername")
    List<Member> findByUsername(@Param("username") String username);
}
  • Query 어노테이션을 생략하고도 Named 쿼리 호출할 수 있다
public interface MemberRepository extends JpaRepository<Member, Long>{
    //@Query(name = "Member.findByUsername")
    List<Member> findByUsername(@Param("username") String username);
}
  • 왜 가능할까?
  • 제네릭에서 해당 repository에 저장할 도메인은 Member로 정했다
  • 그러면 Member.findByUsername이라는 NameQuery를 먼저 찾는다
    • 즉, spring data jpa가 쿼리 메서드를 실행할 때 우선순위가 있다는 것을 의미한다
    • 첫번째로 해당 도메인에 있는 NamedQuery를 먼저 찾고,
    • 두번째로 NamedQuery가 없다면 처음에 배웠던 property 이름을 가지고 생성하는 메서드가 실행된다
    • 우선순위를 변경할 수 있다고 한다! 
      • keyword : query lookup strategies

 

@Query, 메서드에 쿼리 직접 정의

  • 실행할 메서드에 정적 쿼리를 직접 작성
    • 이름 없는 Named Query라고 할 수 있음
  • 애플리케이션 실행 시점에 문법 오류를 발견할 수 있음
    • 매우 큰 장점

public interface MemberRepository extends JpaRepository<Member, Long>{
    @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);
}

 

@NamedQuery는 실무에서 잘 사용하지 않는다?

  • 강의에서 Named Query는 실제로 사용하지 않는다고 함
  • 복잡한 정적 쿼리는 마지막에 배웠던 "메서드에 쿼리 직접 정의"를 사용하고
  • 간단한 정적 쿼리는 처음에 배웠던 "메서드 이름으로 쿼리 생성"을 사용함

 

@Query를 이용하여 DTO 조회

빨강색은 MemberDto 클래스의 경로를 의미하고, 파랑색은 MemberDto의 생성자 형식을 의미한다.

 


REFERENCES

728x90

'Spring 강의 > Spring data JPA' 카테고리의 다른 글

@EntityGraph  (0) 2022.04.13
벌크 연산  (0) 2022.04.12
페이징과 정렬  (0) 2022.04.11
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그