본문 바로가기
JPA

JPQL(객체지향 쿼리 언어)

by Dev_Green 2022. 10. 4.

1. 개요

1) JPA가 지원하는 다양한 쿼리 방법

  1. JPQL
  2. JPA Criteria
  3. QueryDSL
  4. Native SQL
  5. JDBC API

2) JPQL 소개

  • JPA를 사용하면 Entity 객체를 중심으로 개발하지만 SQL은 DB의 테이블을 대상으로 쿼리를 수행
  • 이러한 간극을 보완하기 위해 JPQL은 테이블이 아닌 Entity 객체를 대상으로 쿼리를 수행
  • 즉, JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공함; 특정 DB SQL에 의존하지 않음
  • 이는 SQL문법과 유사하여 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
  • JPQL = 객체지향 SQL ; JPQL은 결국 SQL로 변환됨

 

2. 기본 문법과 기능

1) JPQL 문법

SQL 문법과 대부분 비슷함

select_문 :: =
	select_절
	from_절
	[where_절]
	[groupby_절]
	[having_절]
	[orderby_절]
    
update_문 :: = update_절 [where_절]
delete_문 :: = delete_절 [where_절]

 

  • 엔티티는 대문자로 시작, 속성은 소문자로 시작(Member, age)
  • JPQL 키워드는 대소문자 구분 X(SELECT, FROM 등)
  • 쿼리에 엔티티 이름 사용(테이블 이름이 아닌)
  • 별칭 필수(as는 생략 가능)

2) TypeQuery와 Query

  • TypeQuery: 반환 타입이 명확할 때 사용
TypedQuery<Member> query =
	em.createQuery("SELECT m FROM Member m", Member.class);

 

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

3) 결과 조회 API

    • query.getResultList()
      • 결과가 하나 이상일 때, 리스트 반환
      • 결과가 없으면 빈 리스트 반환
    • query.getSingleResult()
      • 결과가 정확히 하나일 때 사용, 단일 객체 반환
      • 결과가 없으면: javax.persistence.NoResultException
      • 둘 이상이면:  javax.persistence.NonUniqueResultException

4) Parameter Binding

  • 이름 기준
SELECT m FROM Member m where m.username=:username
query.setParameter("username", usernameParam);

 

  • 위치 기준(유지보수 측면에서 불리하므로 비추)
SELECT m FROM Member m where m.username=?1
query.setParameter(1, usernameParam);

 

5) Projection

  • SELECT 절에 조회할 대상을 지정하는 것
  • 프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
    • 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 -> 스칼라 타입 프로젝션
  • 여러 값 조회 방법
    1. Query 타입으로 조회
    2. Object[] 타입으로 조회
    3. new 명령어로 조회
      • 결과값의 형식에 맞는 DTO를 만들고 그 DTO 객체로 결과를 받음 
      • 패키지 명을 포함한 전체 클래스 명 입력
      • 순서와 타입이 일치하는 생성자 필요
SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m

 

6) Paging

  • setFirstResult(int startPosition) : 조회 시작 위치(0부터)
  • setMaxResults(int maxResult) : 조회할 데이터 수
String jpql = "select m from Member m orderby m.name desc";
List<Member> resultList = em.createQuery(jpql, Member.class)
	.setFirstResult(10) // 인덱스 10부터
    	.setMaxResults(20)  // 20개 가져와
    	.getResultList();

 

7) Join

  • Inner Join : 기준 테이블조인 테이블 모두 데이터가 존재해야 조회됨
  • Outer Join: 기준 테이블에만 데이터가 존재하면 조회됨
  • Theta Join: 두 테이블 간의 속성 값을 비교(=,≠,≥,≤,>,<)하여 조건을 만족하는 데이터만 조회
SELECT m FROM Member m [INNER] JOIN m.team t  // 내부 조인
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t  // 외부 조인
SELECT count(m) from Member m, Team t where m.username = t.name // 세타 조인

 

  • ON 절
    1. 조인 대상 필터링 : Ex) 회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인 
    2. 연관관계 없는 엔티티 외부 조인 : Ex) 회원의 이름과 팀의 이름이 같은 대상 외부 조인

'JPA' 카테고리의 다른 글

[JPA] JPA의 Entity에 기본 생성자가 필수인 이유  (0) 2023.12.17
[JPA] N+1 문제 및 해결방안  (0) 2022.10.11