본문 바로가기

JPA/JPQL

조인

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

JPQL에서 조인은 어떻게 하는지 알아보자!!

 

Student.java

package hellojpa;

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

import javax.persistence.*;

@Entity
@Data
public class Student {

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

    private String name;

    private int age;

    @Embedded
    private Address address;

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

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

 

Club.java

package hellojpa;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;

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

    private String name;

    @OneToMany(mappedBy = "club")
    private List<Student> students = new ArrayList<>();
}

 

JpaMain.java - club 및 student 저장로직

Club club = new Club();
club.setName("programming");
em.persist(club);

Student student = new Student();
student.changeClub(club);
student.setName("code-mania");
student.setAge(21);
em.persist(student);

em.flush();
em.clear();

JpaMain.java - join로직

아래에서 표기되는 SQL들은 H2 기준입니다.

 

Inner Join

// select s from Student s join s.club c == inner join
// join 앞에 종류를 명시하지 않으면 기본적으로 inner join
String query = "select s from Student s inner join s.club c";
List<Student> students = em.createQuery(query, Student.class).getResultList();
실질적인 SQL
select student.* from Student student inner join Club club on student.CLUB_ID=club.id

 

Outer Join

String query = "select s from Student s left join s.club c";
List<Student> students = em.createQuery(query, Student.class).getResultList();
실질적인 SQL
select student.* from Student student left outer join Club club on student.CLUB_ID=club.id

 

Cross Join

String query = "select s, c from Student s, Club c where s.name = c.name";
List<Object[]> students = em.createQuery(query).getResultList();
실질적인 SQL
select student.*, club.* from Student student cross join Club club where student.name=club.name

inner 및 outer join의 JPQL문에서는 Student Entity만 들고 왔다.
그렇기때문에 List<Student> 타입으로 결과값을 들고 올 수 있었다.
하지만 Croos Join의 JPQL에서는 Student와 Club 2개의 Entity를 들고 오는데, 이 때는 결과값을 단정지을 수 없다.
따라서 결과값을 List<Object[]> 타입으로 가져와야 한다.
(참고: 크로스 조인은 한 테이블의 행과 다른 테이블의 모든 행을 조인한다.
따라서 조인 후 행의 개수 = table1의 행 * table2의 행이 된다.)

 

Join 시 on을 통한 추가조건 걸기

String query = "select s, c from Student s left join Club c on c.name='programming'";
List<Object[]> students = em.createQuery(query).getResultList();
실질적인 SQL
select student.*, club.* from Student student inner join Club club
on student.CLUB_ID=club.id and ( club.name='programming' )

 

select s, c from Student s inner join s.club c where c.name='programming'
select s, c from Student s inner join s.club c on c.name='programming'

위 두 JPQL의 결과는 같다. 하지만 미묘한 차이가 있다.
1번의 경우 모든 데이터를 join하고 where문으로 거르지만,
2번의 경우 join할 때부터 원하는 데이터만 골라서 join한다.
따라서 성능은 2번쿼리가 더 잘나온다.

 

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

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

N+1과 fetch join  (0) 2021.10.02
경로표현식  (0) 2021.10.02
JPQL 함수  (0) 2021.09.25
JPQL에서의 Enum과 조건식  (0) 2021.09.17
서브쿼리  (0) 2021.09.16