SMALL

Fetch Join은 기본 SQL 문법이 아니다.

JPQL( Java Persistence Query Language)에서 성능 최적화를 위해  제공하는 기능이다. 

연관 Entity or Collection을 SQL 한 번에 조회하기 위해 사용된다. 

JPQL ( Java Persistence Query Language ) : 객체 지향 쿼리 언어 
 - 테이블 대상으로 쿼리를 하는것이 아닌 객체를 대상으로 쿼리
 - SQL를 추상화한 것으로 특정 DB의 SQL에 의존하지 않는다

보통 아래와 같은 형태로 사용된다.

 

@Query("select m from Member m join fetch m.team")

 

실제 사용되는 예시를 보도록하자.

Member, Team Entity가 존재하고 Member는 하나의 Team에 속할 수 있고 Team은 여러 명의 Member를 가질 수 있다.

 

 

위와 같은 형태로 Member의 정보를 조회했을 때 해당 Member가 속한 Team 정보를 조회하고 싶은 경우에 사용될 수 있다.

 

@Getter
@NoArgsConstructor
@Entity
public class Member {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column
	private String name;
	
	@ManyToOne
	private Team team;
	
	@Builder
	public Member(String name) {
		this.name = name;
	}
	
	public void updateTeam(Team team) {
		this.team = team;
	}
}
@Getter
@NoArgsConstructor
@Entity
public class Team {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column
	private String name;
	
	@OneToMany(mappedBy = "team")
	private List<Member> members;
	
	@Builder
	public Team(String name) {
		this.name = name;
	}
}

 

기본적으로 JPA에서 제공하는 findAll 메서드를 호출하게 되면 Member List를 모두 조회해오는 Query와 각각의 Member에 매핑되는 Team을 조회하는 쿼리가 실행하게 된다. 

( 예를 들어 Member의 개수가 N 인 경우 Member List 조회 ( 1 ) + 각 Member에 매핑되는 Team 조회 ( N ) => N +1 )

 

memberRepository.findAll()

Hibernate:
    select member0_.id as id1_2_, member0_.name as name2_2_, member0_.team_id as team_id3_2_ from Member member0_
Hibernate:
    select team0_.id as id1_6_0_, team0_.name as name2_6_0_ from Team team0_ where team0_.id=?
Hibernate:
    select team0_.id as id1_6_0_, team0_.name as name2_6_0_ from Team team0_ where team0_.id=?

 

이러한 문제를 해결하기 위해서 JPQL에서 Fetch Join 기능을 제공한다.

 

public interface MemberRepository extends JpaRepository<Member, Long>{

	@Query("select m from Member m join fetch m.team")
	Set<Member> findAllJoinFetch();
}

 

memberRepository.findAllJoinFetch()

Hibernate: 
    select
        member0_.id as id1_2_0_,
        team1_.id as id1_6_1_,
        member0_.name as name2_2_0_,
        member0_.team_id as team_id3_2_0_,
        team1_.name as name2_6_1_ 
    from
        Member member0_ 
    inner join
        Team team1_ 
            on member0_.team_id=team1_.id

만약 실행되는 Query의 Join 형식도 정하고 싶은 경우에는 아래와 같이 지정하면 된다.

@Query("select m from Member m left join fetch m.team")

 

 

또한 Join을 한 대상에서 한 번 더 Join을 하고 싶은 경우에는 아래와 같이 작성하면 된다.

( Team에 연관 객체로 Coach가 있다고 가정 )

@Query("select m from Member m join fetch m.team t join fetch t.coach")

 

만약 이러한 형태가 아닌 기본 제공하는 findAll을 통해서 연관 객체를 조회하고 싶은 경우에는 FetchType을 EAGER로 지정하면 된다.

@Getter
@NoArgsConstructor
@Entity
public class Team {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column
	private String name;
	
	@OneToMany(mappedBy = "team", fetch = FetchType.EAGER) // !!Added
	private List<Member> members;
	
	@Builder
	public Team(String name) {
		this.name = name;
	}
}

 

LIST

+ Recent posts