일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 1차원 DP
- 2차원 dp
- 99클럽
- @Builder
- @Entity
- @GeneratedValue
- @GenericGenerator
- @NoargsConstructor
- @Query
- @Table
- @Transactional
- Actions
- Amazon EFS
- amazon fsx
- Android Studio
- ANSI SQL
- ApplicationEvent
- assertThat
- async/await
- AVG
- AWS
- Azure
- bind
- builder
- button
- c++
- c++ builder
- c03
- Callback
- case when
- Today
- Total
기록
[JPA] @Query 주의점 : nativeQuery와 @Table(name="orders") 본문
시작하면서
JPA에서 @Query 어노테이션을 사용하여 쿼리를 작성하던 중 문법 오류를 겪었습니다.
이 오류의 원인은 바로 nativeQuery 옵션의 사용 방식에 있었습니다. nativeQuery는 JPQL(JPA Query Language)이 아닌 네이티브 쿼리(데이터베이스 종속적인 쿼리)를 사용하겠다는 의미입니다. 따라서 JPQL 문법으로 작성한 쿼리가 네이티브 쿼리로 처리되면서 문제가 발생한 것입니다.
발생한 오류
아래는 실제로 작성한 코드와 테스트 실행 결과입니다.
@Query(value = "SELECT o FROM orders o " +
"WHERE o.registeredDateTime >= :startDateTime " +
"AND o.registeredDateTime <= :endDateTime " +
"AND o.orderStatus = :orderStatus",
nativeQuery = true)
List<Order> findOrdersBy(LocalDateTime startDateTime, LocalDateTime endDateTime, OrderStatus orderStatus);
테스트를 실행했을 때 발생한 오류는 다음과 같습니다:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "O" not found; SQL statement:
SELECT O FROM orders O WHERE o.registeredDateTime >= ? AND ...
오류 메시지에서 알 수 있듯이, 데이터베이스는 orders 테이블에 o라는 필드를 찾을 수 없다고 말하고 있습니다. 이는 JPQL 문법에서 사용되는 엔티티와 별칭(o)을 네이티브 쿼리 문법으로 해석했기 때문입니다.
문제 해결 방법
이 문제를 해결하기 위해서는 JPQL과 네이티브 쿼리 중 하나를 선택해야 합니다.
1. JPQL 사용
nativeQuery = true를 제거하고 JPQL 문법을 올바르게 사용하면 됩니다. JPQL은 엔티티와 그 필드 이름을 기준으로 작동하므로 데이터베이스와 독립적인 코드를 작성할 수 있습니다.
JPQL 예제
@Query("SELECT o FROM orderEntity o " +
"WHERE o.registeredDateTime >= :startDateTime " +
"AND o.registeredDateTime <= :endDateTime " +
"AND o.orderStatus = :orderStatus")
List<Order> findOrdersBy(LocalDateTime startDateTime, LocalDateTime endDateTime, OrderStatus orderStatus);
이 경우, orderEntity라는 엔티티 이름과 엔티티 필드 이름(registeredDateTime, orderStatus)을 그대로 사용합니다.
2. 네이티브 쿼리 사용
만약 네이티브 쿼리를 사용해야 한다면, 데이터베이스 테이블과 컬럼 이름을 정확히 사용해야 합니다. 아래는 네이티브 쿼리로 작성한 예제입니다.
네이티브 쿼리 예제
@Query(value = "SELECT * FROM orders " +
"WHERE registered_date_time >= :startDateTime " +
"AND registered_date_time <= :endDateTime " +
"AND order_status = :orderStatus",
nativeQuery = true)
List<Order> findOrdersBy(LocalDateTime startDateTime, LocalDateTime endDateTime, OrderStatus orderStatus);
여기서는 실제 데이터베이스 테이블(orders)과 컬럼 이름(registered_date_time, order_status)을 사용했습니다.
JPQL과 네이티브 쿼리 선택
제 경우, 굳이 네이티브 쿼리를 사용할 필요가 없었기 때문에 nativeQuery 옵션을 제거하고 JPQL을 사용했습니다. JPQL은 데이터베이스에 독립적이며, 유지보수가 용이하다는 장점이 있습니다.
@Entity와 @Table의 역할
엔티티 이름과 테이블 이름을 지정하는 방법에도 차이가 있습니다. 아래는 엔티티에 사용하는 주요 어노테이션과 그 목적입니다:
- @Entity: JPA 엔티티 이름을 지정합니다. JPQL에서 이 이름을 사용합니다.
- @Table: 엔티티와 매핑될 데이터베이스 테이블 이름을 지정합니다. 네이티브 쿼리에서 이 이름을 사용합니다.
엔티티 클래스 예제
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity(name = "orderEntity")
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDateTime registeredDateTime;
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus;
// 기타 필드 및 메서드
}
- JPQL을 사용할 경우 orderEntity 이름을 참조합니다.
- 네이티브 쿼리를 사용할 경우 orders 테이블 이름을 참조합니다.
@Query 어노테이션 사용 시 주의점
이번 문제를 통해 @Query 어노테이션 사용 시 몇 가지 주의해야 할 점을 배웠습니다:
- JPQL과 네이티브 쿼리의 차이를 명확히 이해해야 합니다. JPQL은 엔티티와 필드를 기준으로 작성되며, 네이티브 쿼리는 데이터베이스 테이블과 컬럼을 기준으로 작성됩니다.
- nativeQuery = true 옵션을 사용하는 경우, 반드시 데이터베이스와 매핑된 실제 테이블 및 컬럼 이름을 사용해야 합니다.
- 엔티티 이름과 테이블 이름의 구분도 중요합니다. JPQL에서는 @Entity 이름을, 네이티브 쿼리에서는 @Table 이름을 사용해야 합니다.
'Web > Spring' 카테고리의 다른 글
Vaadin 프레임워크 소개: hawkBit 사례 분석(1) (0) | 2025.01.24 |
---|---|
JPA flush()와 clear(): JPA와 QueryDSL 사용 시 발생하는 1차 캐시 동기화 문제 해결하기 (0) | 2025.01.13 |
AWS Elasticache를 Spring Boot에 연결하기 (0) | 2025.01.06 |
JWT와 Redis를 활용한 사용자 인증 프로세스 설계 (0) | 2024.12.31 |
테스트 환경에서의 In-Memory Map을 활용한 로그인/로그아웃 시스템 구현 (0) | 2024.12.30 |