티스토리 뷰

backend/jpa

CH.10 JPQL - 기본 문법

Ribo.Ha 2023. 5. 3. 18:42

JPQL

1. 기본 문법

SELECT, UPDATE, DELETE문을 사용할 수 있고 저장할 때는 em.persist()를 사용하기 때문에 INSERT문은 없다.

  • Member와 m.username과 같은 엔티티와 속성은 대소문자 구분
  • 엔티티 명을 대상으로 한다.
  • 별칭은 필수 (AS 생략 가능)

2. TypeQuery, Query

  • TypedQuery: 반환 타입을 명확하게 지정할 수 있는 경우 TypedQuery 객체 사용
  • Query: 반환 타입을 명확하게 지정할 수 없는 경우 Query 객체 사용
// TypeQuery
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);

List<Member> resultList = query.getResultList();

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

List resultList = query.getResultList();

3. getResultList(), getSingleResult()

  • getResultList(): 결과를 리스트에 담아서 반환 (결과가 없으면 빈 리스트 반환)

  • getSingleResult(): 결과가 정확히 하나일 때 사용

    • 결과가 없으면 javax.persistence.NoResultException 예외 발생

    • 결과가 1개보다 많으면 javax.persistence.NonUniqueResultException 예외 발생

4. 파라미터 바인딩

String usernameParam = "User1";

TypedQuery query = em.createQuery("SELECT m FROM Member m where m.username = :username", Member.class)
                        .setParameter("username", usernameParam);

5. 프로젝션

SELECT로 조회 대상 지정

5.1 엔티티 프로젝션

원하는 엔티티 객체를 조회

  • 조회한 엔티티는 영속성 컨텍스에서 관리
SELECT m FROM Member m;

5.2 임베디드 타입 프로젝션

임베디드 타입 객체를 조회

  • 조회의 시작점이 될 수 없다.
List<Address> addresses = em.createQuery("SELECT o.address FROM Order o", Address.class)
                            .getResultList();

5.3 스칼라 타입 프로젝션

숫자, 문자, 날짜와 같은 기본 데이터를 조회

List<String> usernames = em.createQuery("SELECT DISTINCT username FROM Member m", String.class)
                            .getResultList();

5.4 여러 값 조회

여러 값을 조회

  • 타입이 다르기 때문에 TypedQuery를 사용할 수 없고 Query를 사용해야한다.

  • new 명령어를 사용하여 DTO에 데이터를 담아 전달하면 DTO타입으로 TypedQuery 객체 사용 가능.

    • DTO는 패키지 명을 포함한 전체 클래스 명을 입력해야한다.

    • 생성자의 순서와 타입이 일치해야한다.

public class UserDTO {

    private String username;
    private int age;

    public UserDTO(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

TypedQuery<UserDTO> query = em.createQuery("SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m", UserDTO.class);

6. 페이징 API

  • setFirstResult(10): 조회 시작 위치 (11부터 시작)
  • setMaxResults(20): 조회할 데이터 수(11~30)
TypedQuery query = em.createQuery("SELECT m FROM Member m ORDER BY m.username DESC", Member.class)
                        .setFirstResult(10)
                        .setMaxResults(20);

7. 집합 함수

  • COUNT: 결과 갯수 (반환타입: Long)
  • MAX, MIN: 최대, 최소 (문자, 숫자, 날짜 등에 사용)
  • AVG: 평균 값 (반환타입: Double)
  • SUM: 합 (반환타입: 정수->Long, 소수->Double, BigInteger->BigInteger, BigDecimal->BigDecimal)

7.1 집합 함수 특징

  • NULL은 무시
  • 값이 없는 경우 SUM, AVG, MAX, MINNULL이 되고 COUNT0이 된다.
  • DISTINCT를 집합 함수 안에 사용 가능 (SELCT COUNT(DISTINCT m.age) FROM Member m)
  • DISTINCTCOUNT에서 사용할 때 임베디드 타입은 지원하지 않는다.

8. GROUP BY, HAVING

SELECT t.name, COUNT(m.age), SUM(m.age), AVG(m.age), MAX(m.age), MIN(m.age)
FROM Member m LEFT JOIN m.team t
GROUP BY t.name
HAVING AVG(m.age) >= 10

9. ORDER BY

SELECT m FROM Member m ORDER BY m.age DESC, m.username

Reference

  • 자바 ORM 표준 JPA 프로그래밍 [김영한]

'backend > jpa' 카테고리의 다른 글

Ch.10 JPQL - ETC  (0) 2023.05.03
Ch.10 JPQL - JOIN과 N + 1  (0) 2023.05.03
Ch.9 값 타입  (0) 2023.05.03
Ch.8 프록시와 영속성 전이  (0) 2023.05.03
Ch.7 고급 매핑  (0) 2023.05.03