[Spring Data JPA] 네이티브 쿼리 (Native Query)
포스트
취소

[Spring Data JPA] 네이티브 쿼리 (Native Query)

네이티브 쿼리란?

  • JPA 표준 JPQL 대신 데이터베이스 고유의 SQL 쿼리를 사용하여 엔티티를 조회하는 기능
  • 가급적이면 사용하지 않는 게 좋다.
  • 정말 어쩔 수 없는 경우에만 사용해야 한다.

특징

  • JPQL 제약 극복
    • JPQL로 표현하기 어려운 복잡한 쿼리를 작성할 수 있습니다.
  • 데이터베이스 최적화
    • 데이터베이스 특화 기능을 활용하여 쿼리 성능을 향상시킬 수 있습니다.
  • 유연성
    • 다양한 데이터베이스 플랫폼을 지원한다.

문제점

  • Sort 파라미터를 통한 정렬이 정상 동작하지 않을 수 있다.
    • 믿지 말고 직접 처리하는 것이 좋다.
  • JPQL처럼 애플리케이션 로딩 시점에 문법 확인할 수 없다.
  • 동적 쿼리가 불가능하다.
    • 하이버네이트를 직접 활용하면 가능은 하다.
    • 그냥 JdbcTemplate 또는 myBatis를 사용하는 것이 좋다.

사용 방법

  1. 리포지토리에 네이티브 쿼리를 사용할 메소드를 생성한다.
public interface MemberRepository extends JpaRepository<Member, Long> {
    Member findByNativeQuery(String username);
}
  1. 1번에서 생성한 메소드에 @Query 어노테이션을 추가하고, 쿼리를 작성한 뒤, nativeQuery = true 속성을 명시한다.
public interface MemberRepository extends JpaRepository<Member, Long> {
    @Query(value = "select * from member where username = ?", nativeQuery = true)
    Member findByNativeQuery(String username);
}
  1. 필요한 곳에서 사용한다.
@Test
public void nativeQuery() {
    //given
    Team teamA = new Team("teamA");
    em.persist(teamA);
    
    Member m1 = new Member("m1", 0, teamA);
    Member m2 = new Member("m2", 0, teamA);
    em.persist(m1);
    em.persist(m2);
    
    em.flush();
    em.clear();
    
    //when
    Member result = memberRepository.findByNativeQuery("m1");
    System.out.println("result = " + result);
}
  • 페이징도 적용할 수 있다.
@Query(value = "select m.member_id as id, m.username, t.name as teamName from member m left join team t",
        countQuery = "select count(*) from member",
        nativeQuery = true)
Page<MemberProjection> findByNativeProjection(Pageable pageable);
@Test
public void nativeQuery() {
    //given
    Team teamA = new Team("teamA");
    em.persist(teamA);
    
    Member m1 = new Member("m1", 0, teamA);
    Member m2 = new Member("m2", 0, teamA);
    em.persist(m1);
    em.persist(m2);
    
    em.flush();
    em.clear();
    
    //when
    Page<MemberProjection> result = memberRepository.findByNativeProjection(PageRequest.of(0, 10));
    List<MemberProjection> content = result.getContent();
    for (MemberProjection memberProjection : content) {
        System.out.println("memberProjection = " + memberProjection.getUsername() + " / " + memberProjection.getTeamName());
    }
}

주의 사항

  • JPQL은 위치 기반 파리미터를 1부터 시작하지만 네이티브 쿼리는 0부터 시작한다.
  • 네이티브 쿼리로 엔티티가 아닌 DTO로 조회하기는 JdbcTemplate 또는 myBatis를 사용하는 것이 좋다.
  • 네이티브 쿼리는 데이터베이스 플랫폼에 종속적이기 때문에, 플랫폼이 변경되면 쿼리를 수정해야 된다.
  • JPQL보다 더 복잡하고 오류 가능성이 높다.
  • DTO 대신에 프로젝션으로 조회할 수 있다.

출처

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.