네이티브 쿼리
@Query(
value = "SELECT * FROM users WHERE age >= 20", // 일반적인 SQL
nativeQuery = true
)
List<User> findAdults();
- DB에 직접 SQL 날림
- JPA와 별개로 동작
- 결과를 객체로 매핑만 해줌
JPA 생태계와 독립적으로 날리는 쿼리이다.
즉 DB 종속적이므로 컬럼명이나 테이블명이 변경되면 유지보수가 번거로울 수 있다.
JPQL(Java Persistence Query Language)
일반적인 SQL과 문법이 거의 비슷하지만 살짝 다르다.
@Query(
value = "SELECT * FROM User WHERE age >= 20", // User는 테이블명이 아닌 엔티티명. 대소문자 구별함
)
List<User> findAdults();
- 네이티브 쿼리와는 달리 엔티티 객체를 조회
- 실행 시점에 JPA가 JPQL을 실제 SQL로 변환시킴
- 잘못 쓰면 성능은 네이티브에 비해 느릴 수 있음
여기서 말하는 잘못 쓴 경우는 User에 연관된 엔티티가 있을 때,
연관 객체를 무조건 사용하는데도 FetchType.Lazy를 사용하는 경우 등을 말한다.
즉 잘못된 JPA 설계 문제만 없으면 JPQL은 네이티브 쿼리와 성능이 크게 차이나지 않는다.
하지만 복잡한 쿼리를 필요로 할 땐 이런 정책까지 신경쓰기 힘들 수 있는데,
이럴 때 네이티브 쿼리를 사용하면 최대 성능을 뽑아낼 수 있으니 전략적으로 판단해야 한다.
JPA Criteria
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);
cq.select(user)
.where(cb.greaterThanOrEqualTo(user.get("age"), 20));
List<User> result = em.createQuery(cq).getResultList();
검색 필터 등 동적인 조건을 필요로 할 때 JPQL을 만들어주는 API이다.
참고로 JPQL 예시에 있던 쿼리랑 완전히 같은 쿼리이다.
이와 같이 가독성은 별로 좋지 않으므로 동적 조건이 아니면 사실상 쓸 이유가 거의 없다.
유의해야 될 점은
@Query("SELECT u FROM User u")
List<User> findAll(Specification<User> spec);
이 코드는 안 된다는 점이다.
@Query에서도 JPQL을, Specification에서도 JPQL을 만들고 있는데,
이러면 무조건 @Query쪽만 실행되고 Specification은 무시된다.
Specification을 쓴 이유는 동적 쿼리 때문일 테니 그쪽으로 통일시키는 것이 적절한 방법이다.
이게 사실상 이 포스트를 쓴 이유다...
'IT > Spring & Spring Boot' 카테고리의 다른 글
| [Spring Boot] 통합 회원관리 시스템(IAM) 구현 기록 (1) | 2025.11.26 |
|---|---|
| [Spring Boot/NGINX] 로그 없는 웹소켓 연결 에러 (3) | 2025.07.08 |
| [Java] JVM이 죽었음다 ㅡㅡ; (Java heap space 에러) (1) | 2025.05.18 |
| [IT/일상/Java] MQTT 통신 코드 개선 일지 (feat. QueueChannel, Future) (1) | 2024.12.14 |
| [Spring Boot] RequestBody 필드에 값이 매핑되지 않는 문제 (2) | 2024.11.21 |