Spring 입문 (JPQL, 프로젝션)

KimGwangmin·2026년 9월 8일

JPQL (Java Persistence Query Language)

자바 엔티티 객체와 그 필드를 기준으로 작성하는 쿼리

  • SQL 예: SELECT * FROM members WHERE team_id = 1
  • JPQL 예: SELECT m.username FROM Member m WHERE m.team = ?

SQL과 다른 JPQL 특징

  • 대소문자 구분: 엔티티와 속성은 대소문자 구분
  • 엔티티 이름 사용: 테이블 명이 아닌 엔티티명 사용
  • 별칭(Alias) 필수: 엔티티에는 반드시 별칭 지정

문법: 글에는 기본 조회만 첨부한다.

// 전체 조회
@Query("SELECT m FROM Member m")
List<Member> findAllMembers();

// 조건 조회
@Query("SELECT m FROM Member m WHERE m.age > :age")
List<Member> findByAgeGreaterThan(@Param("age") int age);

// 단일 결과 조회
@Query("SELECT m FROM Member m WHERE m.username = :username")
Optional<Member> findByUsername(@Param("username") String username);

JPA 프로젝션

엔티티의 전체 필드가 아닌, 원하는 필드만 골라서 객체로 받아오는 기술
성능 최적화와 타입 안정성 확보 가능

  1. 인터페이스 기반 프로젝션

    • 조회할 필드의 getter 메서드만 선언한 인터페이스를 만든다.
    • 실행 시점에 Spring Data JPA가 구현 클래스를 알아서 만들어준다.

닉네임만 가져오고 싶을 때

public interface NicknameOnlyDto {
    String getNickname();
}

public interface MemberRepository extends JpaRepository<Member, Long> {
    List<NicknameOnlyDto> findByNickname(String nickname);
}
  1. 클래스 기반(DTO) 프로젝션(추천)

    • DTO 정의 시 조회할 필드의 순서와 타입이 일치하는 생성자 필요 (필드명은 달라도 됨)
@Getter
public class MemberDto {
    private final String username;
    private final String teamName;

    public MemberDto(String username, String teamName) {
        this.username = username;
        this.teamName = teamName;
    }
}

@Query("SELECT new com.member.dto.projection.MemberDto(m.nickname, t.name) " +
           "FROM Member m JOIN m.team t WHERE m.nickname = :nickname")
Optional<MemberDto> findMemberDtoByNickname(@Param("nickname") String nickname);

0개의 댓글