본문 바로가기

Back-End/JPA

Spring DataJpa : 쿼리 메서드 기능

스프링 데이터 JPA는 메서드 이름을 분석해 JPQL 쿼리를 자동 생성 및 실행하는 강력한 기능을 제공. 이를 통해 복잡한 JPQL 작성 없이 간단하게 데이터를 조회할 수 있으며, 밀요에 따라 정적 쿼리도 직접 정의할 수 있다.


1. 순수 JPA에서의 쿼리 메서드 작성

순수 JPA를 사용하면 JPQL 쿼리를 직접 작성해야 한다. 예를 들어, 이름과 나이를 기준으로 데이터를 조회하는 코드는 아래와 같이 작성.

순수 JPA 리포지토리

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 테스트 코드

@Test
public void findByUsernameAndGreaterThan() {
	Member m1 = new Member("AAA", 10);
	Member m2 = new Member("AAA", 20);
	memberJpaRepository.save(m1);
	memberJpaRepository.save(m2);
    
    List<Member> result = memberJpaRepository.findByUsernameAndAgeGreaterThan("AAA", 15);
    assertThat(result.get(0).getUsername()).isEqualTo("AAA");
    assertThat(result.get(0).getAge()).isEqualTo(20);
    assertThat(result.size()).isEqualTo(1);
}

 

2. 스프링 데이터 JPA

스프링 데이터 JPA는 메서드 이름을 기반으로 쿼리를 자동으로 생성. 같은 조회 기능을 아래와 같이 간단히 구현할 수 있다.

public interface MemberRepository extends JpaRepository<Member, Long> {
	
    List<Member> findByUsernameAndGreaterThan(String username, int age);
}
  • 스프링 데이터 JPA는 메서드 이름을 분석해서 JPQL을 생성하고 실행한다.

스프링 데이터 JPA가 제공하는 쿼리 메소드 기능

  • 조회: find...By, read...By, query...By, get...By
    • 예) findHelloBy(중간에 설명을 위한 단어를 넣어도 무방)
  • COUNT: count...By → 반환 타입: long
  • 삭제: delete...By, remove...By → 반환 타입: long
  • LIMIT: findFirst, findTop
  • DISTINCT: findDistinctBy 또는 findMemberDistinctBy
  • EXISTS: exists...By → 반환 타입: boolean
    • 예) findHelloBy (중간에 설명을 위한 단어를 넣어도 무방)

참고 : 이 기능은 엔티티의 필드명이 변경되면 인터페이스에 정의한 메서드 이름도 꼭 함께 변경해야 한다. 그렇지 않으면 애플리케이션을 시작하는 시점에 오류가 발생한다.


3. @Query, 리포지토리 메서드에 쿼리 정의하기

복잡한 쿼리를 정의해야 할 경우 @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);
}

 

  • 정적 쿼리의 장점
    • 문법 오류를 애플리케이션 실행 시점에 감지 기능
    • 복잡한 조건이 많을 때 메서드 이름이 길어지는 문제를 해결
  • 실무에서는 메서드 이름으로 쿼리 생성 기능은 파라미터가 증가하면 메서드 이름이 매우 지저분해지므로 @Query 기능을 자주 사용하게 된다.

4.  DTO 로 직접 조회하기

JPA는 DTO를 조회할 때 new 명령어를 사용한다. 생성자가 매칭되는 DTO 클래스를 작성해야함.

DTO 정의

@Data
public class MemberDto {
	private Long id;
	private String username;
	private String teamName;
	
    public MemberDto(Long id, String username, String teamName) {
        this.id = id;
        this.username = username;
        this.teamName = teamName;
    }
}

DTO 조회 쿼리

@Query("select new study.datajpa.dto.memberdto(m.id, m.username, t.name) " +
		"from member m join m.team t")
List<MemberDto> findMemberDto();

주의! DTO로 직접 조회 하려면 JPA의 new 명령어를 사용해야 한다. 그리고 다음과 같이 생성자가 맞는 DTO가 필요하다.


파라미터 바인딩

파라미터는 이름 기반으로 바인딩하는 것을 권장

public interface MemberRepository extends JpaRepository<Member, Long> {
	@Query("select m from Member m where m.username = :name")
         Member findMember(@Param("name") String username);
}

컬렉션 파라미터 바인딩

Collection 타입으로 in절 지원

@Query("select m from Member m where m.username in :names")
List<Member> findByNames(@Param("names") List<String> names);

6. 단순 값 조회

값 하나를 조회하거나 DTO가 아닌 기본 자료형으로 값을 가져올 수 있다.

@Query("select m.username from Member m")
List<String> findUsernameList();

추가 팁: 실무 활용

  • 메서드 이름 기반 쿼리는 간단한 조회에 유용하지만, 복잡한 조건이나 연산이 필요한 경우 @Query를 선호
  • DTO 조회는 new 키워드로 생성자를 명확히 지정해야 함.
  • 컬렉션 바인딩은 여러 파라미터를 처리할 때 유용.