JPQL의 개념

devlsn96·2024년 10월 28일
0

JPA에서 다양한 쿼리 방법을 지원하는 데 한계가 있고, 특히 검색쿼리 (select)를 실행할 때 복잡한 쿼리문을 가지므로 좀 더 직관적으로 이해하기 쉬운 Query 개념을 소개해본다.

  • JPQL, JPA Criteria(java 표준스펙에서 제공하는 자바 코드를 짜서 JPA를 빌드해주는 generator모음), QueryDSL (JPQL의 한계인 동적인 쿼리에 대한 부분을 보완), 네이티브 SQL(특정 DB에 종속적인 쿼리를 사용해야할 경우), JDBC API를 직접 사용하거나 Mybatis, SpringJDBCTemplate을 함께 사용하여 쿼리를 구현한다.

1. JPQL

JPA를 사용하면, 엔티티 객체를 중심으로 개발할 수 있는데, 검색 쿼리의 경우에도, 테이블이 아닌 엔티티 객체를 대상으로 검색하기 위해서 JPQL을 사용한다.

  • JPA는 SQL을 추상화하는 JPQL이란 객체지향 쿼리 언어(SQL과 문법 유사한 select, from, where, group by, having, join 지원 제공하는 언어로 엔티티 객체를 대상으로 쿼리를 작성한다)
  • SQL은 데이터베이스 테이블을 대상으로 쿼리 작성하는데, SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다.
  • JPA는 JPQL을 분석한 후 적절한 SQL을 만들어 데이터베이스를 조회한다.

🧨 JPQL 사용시, 주의할 사항

  • JPQL 키워드는 대소문자를 구분하지 않지만, 엔티티와 속성은 대소문자를 구분하기 때문에 사용시 주의할 것!
  • 테이블 이름 대신 엔티티 이름을 사용한다.
    - @Entity(name="...")으로 설정 가능 엔티티명 설정 가능하지만, 기본 값을 이름으로 사용하길 추천한다.
  • JPQL의 경우는 별칭은 필수적이다. (AS는 생략 가능하다.)

1-1. JPQL의 문법

  • SQL 쿼리와 문법이 유사하다. (dbms 개념을 참고할 것)
  • select m from Member as m where m.age > 18
    • 엔티티와 속성은 대소문자를 구분해야 하기에, Member나 age로 반드시 대소문자까지 동일하게 작성한다.
    • JPQL키워드는 대소문자를 구분하지 않아도 된다.
      (select, FROM, where, ...)
    • 별칭은 필수값으로 입력한다. (m, as는 생략가능하다)

2. TypeQuery와 Query

2-1. TypeQuery

  • 반환타입이 명확할 때 사용한다.
    TypeQuery<Member> query = em.createQuery("select m from Member m", "Member.class");

2-2. Query

  • 반환타입이 명확하지 않을 때 사용한다.
    Query query = em.createQuery("select m.username, m.age from Member m");

2-3. 결과 조회 API

1) query.getResultList();

  • 결과가 하나 이상일때 리스트 반환하고, 결과가 없으면 빈 리스트를 반환한다.
  • 빈 collection이 반환되기 때문에, NullPointerException에 대한 걱정은 하지 않아도 된다.

2) query.getSingleResult();

  • 단일 객체 반환하는 함수로 결과가 정확히 하나여야 하고, 결과가 없으면 NoResultException를 발생시키고, 둘 이상이면, NonUniqueResultException를 발생시킨다.

2-4. 파라미터 바인딩

1) ✅ 이름 기준

select m from Member m where m.username = :username
query.setParameter("username",usernameParam);

2) 위치 기준

select m from Member m where m.username = ?1
query.setParameter(1, usernameParam);

3. 프로젝션

  • select절에 조회할 대상을 지정하는 것
  • 프로젝션 대상은 엔티티, 임베디드타입, 스칼라 타입 (숫자, 문자등 기본 데이터 타입) 이다.

3-1. 엔티티 조회

select m from Member m

3-2. 임베디드 타입을 조회

select m.address from Member m

3-3. 스칼라 타입을 조회

select m.username, m.age from Member m

페이징 API

JPA는 페이징을 다음 두 API로 추상화할 수 있다.
(몇 번째)부터 (몇 개) 가지고 올래?

1) setFirstResult(int startPosition);

: (0부터 시작하는) 조회 시작 위치

2) setMaxResults(int maxResult);

: 조회할 데이터 수

3-4. 조인 join 엔티티 조회

1) inner join

  • inner는 생략가능하다.
    select m from Member m inner join m.team t

2) outer join

  • outer는 생략가능하다.
    select t from Member m left outer join m.team t

3-5. 서브 쿼리

select m from Member m where m.age > (select avg(m2.age) from Member m2)

  • JPA 표준 스펙에서는 where, having절에서만 서브쿼리 사용하다.
  • (하이버네이트에서 지원해주기 때문에) select 절도 가능하다.
  • from절의 서브쿼리는 현재 jqpl에서 불가능하다.
    (join으로 해결할 수 있으면 해결 가능하다)
profile
Quantum Jump to class for java….

0개의 댓글