본문 바로가기

JPA/JPQL

경로표현식

github 전체코드 주소(branch: JPQL/path)

Student.java

package hellojpa;

import lombok.AccessLevel;
import lombok.Data;
import lombok.Setter;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
public class Student {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String name;

    private int age;

    @Setter(AccessLevel.PROTECTED)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CLUB_ID")
    Club club;

    @OneToMany(mappedBy = "student")
    List<SubjectOfStudent> mySubjects = new ArrayList<>();

    void changeClub(Club club) {
        this.setClub(club);
        club.getStudents().add(this);
    }
}

Subject.java

package hellojpa;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
public class Subject {

    @Id @GeneratedValue
    private Long id;

    private String name;

    private String professor;

}

SubjectOfStudent.java

package hellojpa;

import lombok.Data;

import javax.persistence.*;

@Data
@Entity
public class SubjectOfStudent {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "subject_id")
    Subject subject;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "student_id")
    Student student;
}


필드종류

select s.name from  Student s # 상태필드
join s.club c # 단일값 연관필드
join s.mySubjects sub # 컬렉션 값 연관필드

 

위 JPQL을 보면 .을 찍어 객체그래프를 탐색하고 있다.
이렇게 .으로 객체그래프를 탐색하는 것을 경로표현식이라고 한다.

상태필드(state field): 단순히 값을 저장하기 위한 필드
연관필드(association field): 연관관계를 위한 필드

  • 단일값 연관필드
    대상이 엔티티이다.(ex: s.club)
    사용되는 Annotation: @MayToOne, @OneToOne
  • 컬렉션값 연관필드
    대상이 컬렉션이다.(ex: s.mySubjects)
    사용되는 Annotation: @OneToMany, @ManyToMany


종류에 따른 경로 표현식 특징

  상태필드 단일값 연관필드 컬렉션값 연관필드
추가적인 탐색 가능 여부 X O X
묵시적 내부조인(inner join)
발생 여부
X O O

명시적 조인과 묵시적 조인

# 명시적 조인 JPQL
select sub from  Student s inner join s.mySubjects sub
# 실제 SQL
select sub.id, sub.student_id, sub.subject_id from Student s
inner join SubjectOfStudent sub on s.MEMBER_ID=sub.student_id

# 묵시적 조인 JPQL
select s.mySubjects from Student s
# 실제 SQL
select sub.id, sub.student_id, sub.subject_id from Student s
inner join SubjectOfStudent sub on s.MEMBER_ID=sub.student_id

명시적 조인: join 키워드 직접 사용
묵시적 조인: 경로 표현식에 의해 묵시적으로 실제 SQL에 내부조인 발생

두 개의 조인 모두 결과적으로 생성되는 SQL은 같다.

 

# 명시적 조인 JPQL - 정상작동
select sub.subject from  Student s inner join s.mySubjects sub

# 묵시적 조인 JPQL - 에러발생
select s.mySubjects.subject from Student s

컬렉션값 연관필드로부터 속성을 얻는 것은 불가능하다.

만약에 얻어와야 한다면 명시적 조인을 통해 얻어온 별칭으로 탐색이 가능하다.


경로탐색을 사용한 묵시적 조인 시 주의사항

  • 묵시적 조인은 항상 내부조인을 발생시킨다.
  • 컬렉션에서는 추가적인 경로 탐색이 불가능하고,
    추가적인 경로 탐색을 위해서는 명시적 조인을 통해 얻어온 별칭이 필요하다.
  • 묵시적 조인은 SQL의 FROM(JOIN) 절에 영향을 줄 수 있으며,
    이로 인해 나도 모르게 수많은 조인을 부를 수 있다.
  • 묵시적 조인을 사용하면 JOIN 쿼리의 여부를 한눈에 파악하기 어렵다.
    가급적 묵시적 조인 대신에 명시적 조인을 사용하는 것이 좋다.

 

참고강의: 배달의 민족 개발팀장 김영한 강사님의 JPA 강의

'JPA > JPQL' 카테고리의 다른 글

페치조인 특징과 한계  (0) 2021.10.12
N+1과 fetch join  (0) 2021.10.02
JPQL 함수  (0) 2021.09.25
JPQL에서의 Enum과 조건식  (0) 2021.09.17
서브쿼리  (0) 2021.09.16