JPQL vs Native SQL

이진욱·2024년 12월 26일

이론

목록 보기
19/24

쿼리 문법 자체는 JPQL과 Native SQL의 구분 기준이 아니며, 컴퓨터는 API 사용 방식이나 명시적 설정(e.g., nativeQuery = true)을 통해 쿼리 유형을 판단합니다. JPQL은 실행 전에 JPA가 처리하고 변환하므로 실행 환경에서 차이가 나타납니다.

1. JPQL (Java Persistence Query Language)

  • 특징:

    • 엔티티 중심: JPQL은 데이터베이스의 테이블이 아니라 JPA 엔티티를 대상으로 쿼리합니다. 이는 객체 지향적인 접근 방식을 제공합니다.

    • 데이터베이스 독립성: JPQL은 JPA 구현체(Hibernate 등)에 의해 SQL로 변환되므로 특정 데이터베이스에 종속되지 않습니다.

    • 표준화: JPA 표준 스펙의 일부로, JPA를 사용하는 모든 환경에서 동일하게 동작합니다.

    • 구문: SQL과 유사하지만, 테이블 대신 엔티티 이름과 필드를 사용합니다.

  • 예제:

// JPQL 쿼리
String jpql = "SELECT u FROM User u WHERE u.name = :name";
TypedQuery<User> query = em.createQuery(jpql, User.class);
query.setParameter("name", "John");
List<User> users = query.getResultList();
  • JPQL은 EntityManager 또는 Spring Data JPA에서 명시적으로 사용합니다

    @Query("SELECT u FROM User u WHERE u.name = :name")
    List findByName(@Param("name") String name);

  • 장점:

데이터베이스 변경 시 쿼리를 수정할 필요가 적음.
객체 중심 설계와 잘 맞아 코드의 가독성이 높음.
데이터베이스에 독립적인 코드 작성 가능.

  • 단점:

복잡한 SQL 쿼리를 작성하기 어려움.
데이터베이스 고유 기능(예: 특정 함수 또는 쿼리 힌트) 사용 제한.

2. Native SQL

  • 특징:
    SQL 중심: 데이터베이스의 테이블, 컬럼, SQL 구문을 직접 작성합니다.
    데이터베이스 종속적: 작성한 SQL은 특정 데이터베이스에 종속적이며, 데이터베이스 변경 시 쿼리를 수정해야 할 수 있습니다.

  • 유연성: JPQL보다 더 복잡하고 최적화된 쿼리를 작성할 수 있습니다.

  • 구문: 데이터베이스에서 사용하는 표준 SQL을 사용합니다.

  • Native SQL은 명시적으로 nativeQuery = true로 지정합니다.

nativeQuery = true

@Query(value = "SELECT * FROM users WHERE user_name = :name", nativeQuery = true)
List findByNameNative(@Param("name") String name);

  • 예제:

// Native SQL 쿼리
String sql = "SELECT * FROM users WHERE name = :name";
Query query = em.createNativeQuery(sql, User.class);
query.setParameter("name", "John");
List users = query.getResultList();

  • 장점:

    • 데이터베이스 고유 기능 활용 가능.
    • 복잡한 쿼리와 고성능 쿼리 작성에 유리.
    • 기존 SQL 쿼리 재사용 가능.
  • 단점:

    • 데이터베이스 종속적 코드 작성.
    • 엔티티를 직접 사용하는 JPQL보다 가독성이 낮을 수 있음.
    • 유지보수 비용 증가.

구별하는 방식

만약 엔터티 이름과 테이블 이름이 동일하거나 비슷하게 설계된 경우, 쿼리 문법만 보고 JPQL인지 Native SQL인지 구분하기 어려울 수 있습니다. 하지만 JPA가 제공하는 실행 메커니즘을 통해 내부적으로 이를 명확히 구분할 수 있습니다.

예시: 혼동될 수 있는 경우
@Entity
@Table(name = "users")
public class User {
    @Id
    private Long id;

    private String name;
}
  • JPQL 쿼리

@Query("SELECT u FROM User u WHERE u.name = :name")
List findByName(@Param("name") String name);

  • Native SQL 쿼리

@Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true)
List findByNameNative(@Param("name") String name);

두 쿼리 모두 users라는 테이블 이름(혹은 엔터티 이름)을 사용하기 때문에 문법적으로 유사해 보입니다. 특히 Native SQL의 경우 JPQL처럼 보이는 경우도 있습니다.

컴퓨터가 JPQL과 Native SQL을 구분하는 방식
  • JPA 컨텍스트

JPA는 JPQL 쿼리를 분석하고, 이를 SQL로 변환하는 작업을 수행합니다.
EntityManager 또는 Spring Data JPA의 @Query에서 JPQL인지 Native SQL인지 명시적으로 설정된 옵션을 확인합니다.

예: nativeQuery = true가 설정되지 않은 경우, 쿼리는 기본적으로 JPQL로 간주됩니다.

  • 쿼리 파싱

JPQL은 엔터티 클래스와 필드를 기준으로 작성되기 때문에, JPA는 이를 파싱하여 엔터티와 속성을 매핑합니다.

예: SELECT u FROM User u에서 User는 테이블이 아니라 엔터티 클래스입니다.

  • 쿼리 실행 흐름

    • JPQL: JPA가 JPQL을 SQL로 변환한 후, 변환된 SQL을 데이터베이스로 전달합니다.
    • Native SQL: 작성된 SQL을 변환 없이 그대로 데이터베이스로 전달합니다.
엔터티 이름과 테이블 이름이 동일할 때 혼동 방지
  1. JPQL에서 명확한 엔터티 이름 사용
  • 엔터티 클래스 이름과 필드 이름을 사용하므로, 테이블 이름을 사용하지 않습니다.

    예: @Query("SELECT u FROM User u WHERE u.name = :name")

  1. Native SQL에서 명확한 nativeQuery = true 명시
  • Native SQL인 경우 반드시 nativeQuery = true를 명시하여 구분합니다.

    예: @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true)

  1. 애노테이션 기반 테이블 이름 변경 확인
  • 엔터티 클래스에 명시된 테이블 이름이 실제 테이블 이름과 다를 수 있습니다.

  • Entity 클래스:

@Entity
@Table(name = "members")
public class User {
    private String name;
}
  • JPQL:

@Query("SELECT u FROM User u WHERE u.name = :name")

  • Native SQL:

@Query(value = "SELECT * FROM members WHERE name = :name", nativeQuery = true)

결론

문법적으로 혼동될 수 있는 경우라도, 컴퓨터는 실행 환경(예: nativeQuery 여부, EntityManager)과 엔터티 매핑 정보를 통해 JPQL인지 Native SQL인지 명확히 구분합니다.
개발자는 이러한 메커니즘을 이해하고, 쿼리를 작성할 때 명시적으로 구분하는 것이 중요합니다.

profile
열심히 하는 신입 개발자

0개의 댓글