백엔드/Spring

[Spring] JPA - JPQL(Java Persistence Query Language)

kwang2134 2024. 9. 13. 17:09
728x90
반응형
728x90

JPQL (Java Persistence Query Language)

  • JPA에서 사용하는 쿼리 언어로 테이블을 대상으로 하는 SQL과 다르게 자바 객체를 대상으로 쿼리
  • JPQL 쿼리는 EntityManager를 통해 실행
  • 기본적인 쿼리는 SELECT, UPDATE, DELETE, JOIN 등의 SQL 구문과 유사하나 객체를 대상으로 사용
  • 쿼리 내 엔티티와 엔티티의 속성은 대소문자를 구분
  • 별칭을 필수로 사용 
  • 엔티티, 임베디드, 스칼라 타입에 대해 프로젝션 가능

사용법

  • EntityManager의 createQuery()의 파라미터에 JPQL 문을 넣어 사용
  • 예시) em.createQuery("select m from Member m") -> 반환 타입 Query 인터페이스
  • 반환 타입을 명시적으로 지정하여 사용 가능 
  • 예시) em.createQuerty("select m from Member m", Member.class) -> 반환 타입 TypedQuery<Member>
  • 파라미터를 바인딩하여 사용 가능
  • 예시) em.createQuerty("select m from Member m where m.id = :id", Member.class).setParameter("id", 1)
  • 주요 메서드
    • .getResultList(): 반환 값을 List 형태로 변환하여 반환
    • .getSingleResult(): 단일 결과를 반환 -> 결과가 없거나 1개 이상일 경우 오류 발생
    • .setFirstResult(): 페이징 처리, 쿼리 결과의 시작 위치 지정
    • .setMaxResults(): 페이징 처리, 쿼리 결과의 최대 개수 설정
    • .setHint(): 쿼리 실행에 대한 힌트 지정

조건식

//CASE 문
CASE 
    WHEN condition THEN result
    [WHEN ...]
    [ELSE default_result]
END

 

  • SQL의 case문과 유사
  • 조건에 따라 값을 선택

NULLIF(expression1, expression2)

  • 두 값이 같을 때 NULL을 반환하고 그렇지 않으면 첫 번째 값을 반환

COALESCE(expression1, expression2, ..., expressionN)

  • 인수 목록에서 첫 번째 NULL이 아닌 값을 반환

경로 표현식

  • 상태 필드
    • 단순한 엔티티의 직접적인 속성에 접근
    • 경로 탐색의 끝
  • 단일 값 연관 경로
    • 나의 엔티티와 연관된 다른 단일 엔티티를 참조할 때 사용
    • 단일 객체를 반환
    • 일대일(One-to-One) 또는 다대일(Many-to-One) 관계를 표현
    • 예시) [JPQL] select o.member from Order o
    • member를 탐색하기 위해 묵시적인 내부 조인 발생
    • SQL: select m.* from Orders o inner join Member m on o.member_id = m.id
  • 컬렉션 값 연관 경로
    • 하나의 엔티티와 연관된 여러 엔티티를 참조할 때 사용
    • 일대다(One-to-Many) 또는 다대다(Many-to-Many) 관계를 표현
    • 예시) [JPQL] select o.members from Order o 
    • 컬렉션 연관 경로의 경우 컬렉션이 반환되기 때문에 엔티티의 탐색이 불가능함 -> members.name 등으로 접근 불가능(List에 담겨있는 객체의 내부 필드에 바로 접근하지 못하는 것과 비슷한 개념)

페치 조인 fetch join

  • JPQL에서 성능 최적화를 위해 사용되는 기법
  • 기본적으로 엔티티와 그 연관된 엔티티를 함께 조회할 때 사용
  • join fetch 명령어를 통해 사용 가능
  • 예시) [JPQL] select m from Member m join fetch m.team
  • [SQL] SELECT M.*, T.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID=T.ID
  • 지연 로딩으로 설정된 경우 일반 조인 사용 시 연관된 엔티티가 로드되지 않아 N+1 쿼리가 발생
  • 페치 조인 사용 시 지연 로딩으로 설정되어도 관련 엔티티 즉시 로딩 가능
  • 제한 사항
    • 페치 조인을 사용할 때, 연관된 엔티티가 다수일 경우 중복 데이터가 발생할 수 있음
    • 데이터베이스를 기준으로 결과를 반환하기 때문에 데이터베이스에 실제 반환되는 쿼리 수가 10개라면 동일한 결과의 코드가 10개가 반환됨 -> DISTINCT를 사용하여 중복 제거 
    • 페치 조인으로 인해 데이터가 예상보다 많아질 경우, 쿼리 성능이 저하될 수 있음
    • 페치 조인 대상에는 별칭 지정 불가
    • 컬렉션을 페치 조인 시 페이징 API 사용 불가

다형성 쿼리 TREAT

  • 객체 지향 프로그래밍에서의 다형성을 활용하여 쿼리를 작성하는 기능
  • 상속 구조를 가진 엔티티 클래스들 간의 관계를 쿼리 할 때 사용
  • 예시) [JPQL] select i from Item i where treat(i as Book).author = ‘kim’
  • [SQL] select i.* from Item i where i.DTYPE = ‘B’ and i.author = ‘kim
  • 타입 캐스팅 하듯이 사용

벌크 연산

  • 데이터베이스에 대해 대량의 데이터를 효율적으로 처리할 수 있는 쿼리 작업
  • 주로 대량의 데이터 수정(UPDATE)이나 삭제(DELETE)를 한 번의 쿼리로 처리할 때 사용
  • 특정 조건에 맞는 데이터를 한 번의 쿼리로 수정하는 방식

벌크 연산 주의점

  • 영속성 컨텍스트 동기화 문제
    • 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리를 실행
    • 벌크 연산 실행 시 데이터베이스에 실제 업데이트가 이루어짐
    • 데이터베이스의 값은 변경되었으나 영속성 컨텍스트의 값은 변경되지 않음
    • 영속성 컨텍스트를 초기화하지 않을 시 1차 캐시에 저장된 정보를 반환
    • 실제 데이터베이스의 정보와 일치하지 않음
    • 해결법) 벌크 연산 후에는 영속성 컨텍스트를 초기화하거나, 벌크 연산 전에 플러시를 수행 
  • 엔티티 리스너와의 상호작용
    • 벌크 연산은 엔티티 리스너(@PrePersist, @PostUpdate)와 같은 엔티티의 라이프사이클 콜백을 호출하지 않음
    • 엔티티의 상태가 변경된 것을 감지하지 않아 관련된 로직이 필요하다면 수동으로 처리

자바 ORM 표준 JPA 프로그래밍 - 기본편 강의 | 김영한 - 인프런 (inflearn.com) 강의 내용 참고

 

728x90

'백엔드 > Spring' 카테고리의 다른 글

[Spring] JPA 지연 로딩 & 조회 성능 최적화  (0) 2024.09.20
[Spring] API  (1) 2024.09.19
[Spring] JPA 값 타입  (0) 2024.09.12
[Spring] JPA 프록시  (0) 2024.09.11
[Spring] 연관관계 매핑  (0) 2024.09.10