on
[Spring Data JPA] JPQL
[Spring Data JPA] JPQL
1. 개요
JPA를 사용하면 Entity 객체를 중심으로 개발을 할텐데, 이때 문제는 검색 쿼리입니다. 따라서, 세심한 검색을 위해 쿼리를 짤 수 있어야 하고, JPA는 JPQL이라는 SQL을 추상화한 객체 중심 SQL을 제공합니다. JPQL은 테이블이 아닌 Entity 객체를 대상으로 검색합니다.
JPQL은 ANSI 표준에 나와있는 모든 SQL을 지원합니다.(SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN)
2. 프로젝션
SELECT절에 조회할 대상을 프로젝션이라고 하고, Entity, Embedded 타입, 스칼라 타입(기본 데이터 타입)이 있습니다.
SELECT m FROM Member m // 엔티티 프로젝션 SELECT m.team FROM Member m // 엔티티 프로젝션 SELECT m.address FROM Member m // 임베디드 타입 프로젝션 SELECT m.username, m.age FROM Member m // 스칼라 타입 프로젝션
Entity와 Embedded 타입 프로젝션은 클래스로 조회 값을 받을 수 있으니 명확합니다. 문제는 Scala 타입 프로젝션인데요,
Scala 타입 프로젝션은 다음과 같이 조회 값을 받을 수 있습니다.
1. Query 타입으로 조회
Query query = em.createQuery("SELECT m.username, m.age FROM Member m"); List resultList = query.getResultList(); Object[] o = (Object[]) resultList.get(0); // Object 배열로 타입 캐스팅이 필요합니다. System.out.println("username = " + o[0]); System.out.println("age = " + a[1]);
2. new 키워드를 이용해 DTO에 담아 조회 (쿼리가 문자열이라 패키지명을 모두 명시해야 합니다.)
TypedQuery query = em.createQuery("SELECT new com.demo.dto.MemberDTO(m.username, m.age) FROM Member m");
3. 페이징 API
JPA는 페이징을 다음 두 API로 추상화합니다.
setFirstResult(int startPosition): 조회 시작 위치(0부터 시작)
setMaxResults(int maxResult): 조회할 데이터 수
em.createQuery("SELECT m FROM Member m ORDER BY m.age DESC", Member.class) .setFirstResult(1) .setMaxResults(10) .getResultList();
4. JOIN
ON 절을 활용한 조인은 JPA 2.1부터 지원합니다.
1. JOIN 대상 필터링
String query = "SELECT m FROM Member m JOIN m.team t ON t.name = '회계팀'"; em.createQuery(query, Member.class).getResultList();
2. 연관 관계가 없는 Entity와 외부 JOIN. Hibernate 5.1부터 지원하고 JOIN절에 m.team 형태가 아닌 Team과 같이 엔티티명을 명시
String query = "SELECT m FROM Member m JOIN Team t ON m.username = t.name"; em.createQuery(query, Member.class).getResultList();
5. Subquery
기본 형태는 다음과 같습니다.
String query = "SELECT m FROM Member m" + "WHERE m.age > (SELECT avg(m2.age) FROM Member m2)";
JPA 서브 쿼리의 한계는 다음과 같습니다.
JPA 표준 스펙은 WHERE, HAVING절에서만 서브 쿼리 사용이 가능합니다. 표준은 아니지만 Hibernate는 SELECT절에서도 서브 쿼리를 지원합니다. FROM절에서의 서브 쿼리는 현재 JPQL에서 불가능 합니다. 따라서 JOIN으로 풀어서 해결해야 합니다.
6. 조건식
// 기본 CASE 식 SELECT CASE WHEN m.age <= 10 THEN '학생요금' WHEN m.age >= 60 THEN '경로요금' ELSE '일반요금' END FROM Member m // 단순 CASE 식 SELECT CASE t.name WHEN '팀A' THEN '인센티브110%' WHEN '팀B' THEN '인센티브120%' ELSE '인센티브105%' END FROM Team t
7. JPQL 기본 함수
JPQL은 ANSI 표준 SQL 제공 함수를 똑같이 제공합니다.
from http://pangtrue.tistory.com/347 by ccl(A) rewrite - 2021-12-04 20:01:44