jujuwon
시크릿주주
jujuwon
전체 방문자
오늘
어제
  • 분류 전체보기 (106)
    • 🔠 프로그래밍언어 (35)
      • ☕️ Java (19)
      • 🐠 Python (15)
      • 🍠 Kotlin (1)
    • 🔙 Backend (16)
      • 🌿 Springboot (12)
      • 🐳 Docker (1)
      • ☁️ AWS (3)
    • 💼 CS (12)
      • 📶 Network (12)
    • 🕹 알고리즘 (14)
      • 📑 스터디 (2)
      • 💁🏻‍♂️ 백준 (9)
      • 👨🏼‍🔬 프로그래머스 (3)
    • 📚 Book (8)
      • 🔎 오브젝트 (4)
      • 🧪 TDD (2)
      • 📜 논문 (2)
    • 🔐 보안 (7)
      • 👾 Pwnable (7)
    • 📝 회고 (4)
    • 🧩 etc. (10)
      • ⚠️ issue (2)
      • 💡 꿀팁 (7)
      • ✏️ 끄적 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 글

hELLO · Designed By 정상우.
jujuwon

시크릿주주

JPA :: Query Method 기능
🔙 Backend/🌿 Springboot

JPA :: Query Method 기능

2022. 8. 16. 10:09
반응형

스프링 데이터 JPA 가 제공하는 마법같은 기능이 있다.

바로 “쿼리 메소드” 기능인데, 결론부터 말하면 3가지 기능이 있다.

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

 

Method 이름으로 Query 생성


  • 메소드 이름을 분석해서 JPQL 쿼리 실행
  • 예) 이름과 나이를 기준으로 회원을 조회하려면 ?
// 순수 JPA Repository
public List<Member> findByUsernameAndAgeGreaterThan(String username, int age) {
    return em.createQuery("select m from Member m where m.username = :username and m.age > :age")
    .setParameter("username", username)
    .setParameter("age", age)
    .getResultList();
}

 

데이터 JPA 가 아닌 순수 JPA 로 구현하려면 위 코드처럼 직접 JPQL 을 이용해서 짜면 된다.

스프링 데이터 JPA 로 해당 함수를 만들어보자.

 

public interface MemberRepository extends JpaRepository<Member, Long> {
    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}

 

끝났다. 인터페이스만 정의해도 메소드 이름을 가지고 알아서 쿼리를 만들어서 던져준다.

진짜 생성되는 쿼리를 비교해보아도 동일하게 출력되는 걸 확인할 수 있다.

메소드 이름을 정의할 때 관례대로 적어주기만 하면 된다.

단, 메소드 이름을 내 마음대로 지정하면 당연히 동작하지 않는다 😊

  • 일부러 내 맘대로 메소드 이름 바꾸고 테스트 해보기

 

username2 를 찾지 못했다는 에러가 뜬다.

그럼 메소드 이름을 어떻게 정의해야 할까 ?

그건 아래 스프링 데이터 JPA 공식 문서를 참고하자 (영어에 익숙해지자 🙂)

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

 

  • 조회 : 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 : findFirst3, findFirst, findTop, findTop3

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.limit-query-result

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

 

참고 : 엔티티 필드명이 변경되면 메소드 이름도 꼭 함께 변경해야 한다 !

그렇지 않으면 어플리케이션 로딩 시점에 에러 발생

어플리케이션 로딩 시점에 에러를 인지할 수 있는 것이 스프링 데이터 JPA 의 큰 장점 !

 

JPA NamedQuery


  • @NamedQuery 어노테이션으로 Named Query 정의
@Entity
@NamedQuery(     
	name="Member.findByUsername",
	query="select m from Member m where m.username = :username")
public class Member {
	...
}

 

  • JPA 를 직접 사용해서 Named 쿼리 호출
public class MemberRepository {
  public List<Member> findByUsername(String username) {
    ...
    List<Member> resultList =
      em.createNamedQuery("Member.findByUsername", Member.class)
        .setParameter("username", username)
        .getResultList();
  }
}

 

  • 스프링 데이터 JPA 로 NamedQuery 사용
@Query(name = "Member.findByUsername") // 없어도 잘 동작
List<Member> findByUsername(@Param("username") String username);

 

  • 스프링 데이터 JPA는 선언한 *"도메인 클래스 + .(점) + 메서드 이름"* 으로 Named 쿼리를 찾아서 실행
  • 필요하면 전략을 변경할 수 있지만 권장하지 않는다 !
  • NamedQuery 를 먼저 찾고, 실행할 NamedQuery 가 없으면 메소드 이름으로 쿼리 생성 전략을 사용한다.

실무에서 NamedQuery 를 직접 등록해서 사용하는 일은 드물다고 한다.

대신 @Query 를 사용해서 Repository 메소드에 쿼리를 직접 정의한다.

NamedQuery 의 장점은 어플리케이션 로딩 시점에 문법 오류를 발견할 수 있다는 것!

@Query , Repository 메소드에 쿼리 정의하기


  • 메소드에 JPQL 쿼리 작성
    • @org.springframework.data.jpa.repository.Query 어노테이션을 사용
    • 실행할 메서드에 정적 쿼리를 직접 작성하므로 이름 없는 Named 쿼리라 할 수 있다.
    • JPA Named 쿼리처럼 애플리케이션 실행 시점에 문법 오류를 발견할 수 있음(매우 큰 장점!)
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);
}

 

메소드 이름으로 쿼리 생성 기능은 파라미터가 증가하면 메서드 이름이 매우 지저분해진다.

그래서 실무에서는 @Query 기능을 자주 사용하게 된다고 한다!

 

728x90
반응형
저작자표시 (새창열림)
    '🔙 Backend/🌿 Springboot' 카테고리의 다른 글
    • JPA :: 벌크성 수정 쿼리
    • JPA :: 페이징과 정렬
    • Spring Boot :: Spring Data 패키지 구조
    • Spring Boot :: Spring Data JPA
    jujuwon
    jujuwon

    티스토리툴바