[JPA] JPQL 기본

김용현·2024년 1월 2일
0

JPA

목록 보기
9/12

본 포스트는 김영한 님의 자바 ORM 표준 JPA 프로그래밍 강의를 토대로 작성하였습니다.

JPQL이란?

JPA에서 지원하는 SQL을 추상화한 객체지향 쿼리 언어 이다. 특징은 테이블이 아닌 객체를 대상으로 쿼리를 진행하며, SQL을 추상화해서 특정 데이터베이스 SQL에 종속되지 않는다.
즉, 객체 대상으로 한 SQL 문이 JPQL 이고 JPA가 이걸 실제 데이터베이스를 대상으로 한 SQL 문법으로 바꾸어(각 DBMS용 SQL에 맞게) 쿼리를 날려준다.

JPQL 관련

TypedQuery, Query

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

Query : 반환 타입이 명확하지 않을 때 사용
예시)

Query query = em.createQuery("SELECT m.username, m.age from Member m");

결과 조회 API

query.getResultList() : 결과가 하나 이상일 때 리스트 반환

  • 결과가 없으면 빈 리스트 반환

query.getSingleResult() : 결과가 정확히 하나, 단일 객체 반환

  • 결과가 없으면 : NoResultException
  • 결과가 둘 이상이면 : NonUniqueResultException

JPQL 문법

  • 예시) select m from Member as m where m.age > 18
  • 엔티티와 속성은 대소문자 구분을 한다. (Member, age)
  • JPQL 키워드는 대소문자 구분을 하지 않는다. (SELECT, FROM, where)
  • DB 테이블 이름이 아닌 엔티티 이름을 사용해야 한다. (Member)
  • 별칭은 필수이다(m) 단, as는 생략 가능

프로젝션

SELECT 절에 조회할 대상을 지정하는 것
프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입

여러 값을 조회하는 경우

예시 코드

select m.username, m.age from Member m
  1. Query 타입으로 조회
    -> 특정한 타입을 명시하지 않으면 Query 형태로 조회된다. 예시는 아래를 참고하자.

  2. Object[] 타입으로 조회

     List resultList = em.createQuery("select m.username, m.age from Member m")
                 .getResultList();
    
    Object o = resultList.get(0);
    Object[] result = (Object[]) o;
    System.out.println("username = " + result[0]);
    System.out.println("age = " + result[1]);

    다음과 같이 createQuery 함수에 두 번째 인자로 클래스를 적어주지 않으면 그냥 Object[] 를 담은 List가 반환된다. 따라서 다음과 같이 사용할 수 있다.

  3. new 명령어로 조회

    List<MemberDTO> resultList = em.createQuery("select new com.example.jpabook.jpashop.domain.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
                      .getResultList();

    위 코드와 같이 new 명령어를 작성해주고 반환을 DTO로 받는 형태이다. 이 때 DTO에 정의된 생성자를 이용하므로 쿼리문 형식에 해당하는 생성자가 반드시 존재해야 한다.

페이징

  • setFirstResult(int startPosition): 조회 시작 위치(0부터 시작)
  • setMaxResults(int maxResult): 조회할 데이터 수

코드

  List<Member> result = em.createQuery("select m from Member m order by m.age desc", Member.class)
                .setFirstResult(0)
                .setMaxResults(10)
                .getResultList();

  System.out.println("resultSize: " + result.size());

  for (Member member1 : result) {
  System.out.println("member1 = " + member1);
  }

다음과 같이 시작할 인덱스와 몇 개 가져올지만 정해주면 된다. (정말 간단하다!)

조인 연산

  • 내부 조인
    SELECT m FROM Member m [INNER] JOIN m.team t
    inner는 생략 가능하다. 내부 조인 시 두 테이블에 모두 데이터가 존재해야 가져온다.

  • 외부 조인
    SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
    outer는 생략 가능하다. 두 테이블 중 하나에 데이터가 없더라도 모두 긁어온다.

  • 세타 조인
    SELECT count(m) FROM Member m, Team t where m.username = t.name
    전혀 관계가 없는 Member와 Team 테이블을 카르테시안 곱해서 모두 가져온 뒤 where 절의 조건에 따라 필터링해서 가져온다.

서브 쿼리

쿼리 안에 쿼리를 넣을 수 있다. 이 안에 넣은 쿼리를 서브 쿼리라고 한다.
예시 코드)

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

JPA 서브 쿼리 한계

  • JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
  • SELECT절도 가능(하이버네이트에서 지원)
  • 하이버네이트 6.0부터는 FROM 절에서도 사용 가능
profile
평생 여행 다니는게 꿈 💭 👊 😁 🏋️‍♀️ 🦦 🔥

0개의 댓글