JPA
JPQL 문법 완벽 가이드: JPA를 위한 쿼리 작성법
초코너무조코
2025. 6. 5. 20:38
728x90
Java Persistence API(JPA)를 사용할 때 객체 지향 패러다임을 유지하면서 데이터베이스를 조회하기 위해서는 Java Persistence Query Language(JPQL) 를 이해해야 합니다. JPQL은 SQL과 유사하지만, 테이블이 아닌 엔티티와 그 관계를 대상으로 질의를 수행한다는 점이 특징입니다. 본 글에서는 JPQL의 핵심 문법과 실전 예제, 그리고 성능 최적화 팁까지 한 번에 정리해 보겠습니다.
1. JPQL 기본 구조
JPQL의 구문은 SQL과 유사하나, 주요 키워드와 대상이 엔티티임을 기억하세요.
// JPQL 기본 예시
String jpql = "SELECT m FROM Member m WHERE m.age > 20";
절 | 설명 |
SELECT | 반환할 엔티티(또는 필드) 지정 |
FROM | 조회 대상 엔티티 지정 |
WHERE | 조건식 작성 |
ORDER BY | 정렬 |
GROUP BY / HAVING | 그룹화, 그룹 조건 |
1.1 SELECT 절
- 엔티티 전체: SELECT m FROM Member m
- 특정 필드: SELECT m.username FROM Member m
- 새 DTO: SELECT new com.example.dto.MemberDto(m.username, m.age) FROM Member m
1.2 WHERE 절
- 비교 연산자: =, <, >, <=, >=, <>
- BETWEEN, LIKE, IS NULL, MEMBER OF 등 사용 가능
SELECT m FROM Member m WHERE m.username LIKE '%kim%'
2. 경로 탐색(Path Expressions)과 조인
객체 그래프를 탐색하거나 연관 관계를 명시적으로 조인할 수 있습니다.
2.1 내부 조인 (Inner Join)
SELECT m FROM Member m JOIN m.team t WHERE t.name = '개발팀'
2.2 외부 조인 (Left/Right Outer Join)
SELECT m FROM Member m LEFT JOIN m.team t
2.3 컬렉션 조인
SELECT o FROM Order o JOIN o.orderItems i WHERE i.price > 10000
Tip: 필요에 따라 FETCH JOIN을 사용해 N+1 문제를 해결하세요.
3. 서브쿼리
JPQL은 FROM 절을 제외한 모든 곳에서 서브쿼리를 지원합니다.
SELECT m FROM Member m WHERE m.age > (
SELECT AVG(m2.age) FROM Member m2
)
4. 그룹화와 집계 함수
SELECT t.name, COUNT(m) FROM Team t JOIN t.members m GROUP BY t.name HAVING COUNT(m) >= 3
집계 함수: COUNT, SUM, AVG, MAX, MIN
5. 타입 표현식(Type Expressions)과 다형성 쿼리
상속 관계 매핑 시 TYPE 또는 TREAT 키워드로 서브 타입을 다룰 수 있습니다.
SELECT i FROM Item i WHERE TYPE(i) IN (Book, Movie)
6. JPQL 함수
표준 함수뿐 아니라 방언(Dialect)별 사용자 정의 함수도 호출 가능합니다.
6.1 문자열 함수
- CONCAT, SUBSTRING, TRIM, LOWER / UPPER
6.2 숫자 함수
- ABS, MOD, SQRT
6.3 날짜/시간 함수 (JPA 2.2+)
- CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP
SELECT FUNCTION('group_concat', m.username) FROM Member m
7. 파라미터 바인딩
7.1 이름 기반 파라미터
String jpql = "SELECT m FROM Member m WHERE m.username = :username";
query.setParameter("username", "kim");
7.2 위치 기반 파라미터 (Deprecated)
String jpql = "SELECT m FROM Member m WHERE m.username = ?1";
추천: 가독성과 유지보수를 위해 이름 기반 파라미터를 사용하세요.
8. 벌크 연산 (UPDATE, DELETE)
int count = em.createQuery("UPDATE Member m SET m.age = m.age + 1 WHERE m.age >= 20")
.executeUpdate();
8.1 벌크 연산 시 주의 사항
- 벌크 연산은 영속성 컨텍스트를 무시하고 바로 DB에 반영됩니다.
- 영속성 컨텍스트 초기화(clear) 또는 flush 필요.
em.flush();
em.clear();
9. 네이티브 쿼리와 JPQL의 차이
구분 | JPQL | 네이티브 SQL |
대상 | 엔티티 및 속성 | 테이블 및 컬럼 |
이식성 | 높음 | 낮음(DB 종속) |
성능 최적화 | 페치 조인, 배치 사이즈 등 | DB/Hibernate 튜닝 |
사용 목적 | 일반 조회 | 복잡한 DB 특화 기능, 성능 튜닝 |
10. 성능 최적화를 위한 팁
- 페치 조인(FETCH JOIN) 으로 지연 로딩 문제 해결
- 필요 시 DISTINCT 로 중복 제거
- 하이버네이트 전역 설정 hibernate.default_batch_fetch_size 로 컬렉션 배치 로딩
- 쿼리 캐시와 2차 캐시 적극 활용
결론
JPQL은 JPA를 사용하는 개발자라면 반드시 알아야 할 핵심 기술입니다. 객체 지향 모델에 맞춘 질의를 작성하면 유지보수성과 가독성이 크게 향상됩니다. 본 가이드를 통해 기본 문법부터 성능 최적화 팁까지 익혀 생산성을 높여보세요!
참고 자료
- Java Persistence with Hibernate, 2nd Edition
- 자바 ORM 표준 JPA 프로그래밍 – 김영한
- Hibernate 공식 매뉴얼
728x90