JPA에서 직접 Query를 사용하는 방법들

StrayCat·2026년 2월 14일

1. JPQL

JPA가 기본 제공하는 객체 쿼리 언어. SQL과 비슷하지만 테이블이 아닌 엔티티를 대상으로 한다.

@Query("SELECT m FROM Member m WHERE m.age > :age AND m.team.name = :teamName")
List<Member> findByCondition(@Param("age") int age, @Param("teamName") String teamName);

한계 : 문자열이라 컴파일 타임에 오류를 잡을 수 없고, 동적 쿼리 작성이 불편하다.


2. Native Query (순수 SQL)

DB에 직접 날리는 순수 SQL. 복잡한 쿼리나 DB 종속 기능이 필요할 때 사용한다.

@Query(value = "SELECT m.*, COUNT(o.id) as order_count " +
               "FROM members m " +
               "LEFT JOIN orders o ON m.id = o.member_id " +
               "GROUP BY m.id " +
               "HAVING order_count >= :minOrders",
       nativeQuery = true)
List<Object[]> findActiveMembers(@Param("minOrders") int minOrders);

3. QueryDSL

타입 안전한 동적 쿼리를 자바 코드로 작성할 수 있다. 가장 널리 쓰이는 조합.

public List<Member> searchMembers(String name, Integer minAge, String teamName) {
    BooleanBuilder builder = new BooleanBuilder();

    if (name != null) builder.and(member.name.contains(name));
    if (minAge != null) builder.and(member.age.goe(minAge));
    if (teamName != null) builder.and(member.team.name.eq(teamName));

    return queryFactory
            .selectFrom(member)
            .leftJoin(member.team, team).fetchJoin()
            .where(builder)
            .orderBy(member.id.desc())
            .fetch();
}

장점 : 컴파일 타임 오류 체크, 자동완성, 조건 조합이 자유로움


4. MyBatis 와 혼용

프로젝트에서 JPA와 MyBatis를 같이 쓰는 것도 가능하다. 통계나 리포트처럼 복잡한 조회는 MyBatis로, 일반 CRUD는 JPA로 분리하는 패턴.


판단 기준

상황추천 방식
단순 CRUDSpring Data JPA 메서드
조건 검색, 동적 쿼리QueryDSL
DB 함수, 윈도우 함수 등Native Query
대량 INSERT/UPDATENative Query 또는 JDBC 직접 사용
복잡한 통계 / 리포트Native Query 또는 MyBatis 혼용

핵심은 유연하게, 적재적소에 사용하는 것. JPA를 쓴다고 해서 모든 걸 ORM으로만 해결해야 하지 않음. 단순한 것은 JPA에게 위임하고, 복잡한 것은 직접 쿼리를 작성하는 것이 현실적인 접근임.

profile
알면 좋은 것보단 잊어버리기 싫은 것들을 기록합니다.

0개의 댓글