Skip to content

Latest commit

 

History

History
181 lines (148 loc) · 4.2 KB

fetch-join-jpql-entitygraph.md

File metadata and controls

181 lines (148 loc) · 4.2 KB

Fetch Join - JPQL, EntityGraph

  • 페치 조인은 기존 SQL에 속하는 조인은 아니고 JPQL의 성능 튜닝을 위해 제공되는 조인이다.
  • 페치 조인을 사용하면 관련 엔티티(테이블)까지 모두 조회하는 것을 말하며 N+1 문제 해결로 자주 사용된다.

구현

@Entity
public class Post {

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

	@OneToMany(mappedBy = "post")
	private List<Comment> comments = new ArrayList<>();
}
@Entity
public class Comment {

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

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "post_id")
	private Post post;
}

JPQL

public interface CommentRepository extends JpaRepository<Comment, Long> {

	@Query("select c from Comment c join fetch c.post where c.id = :comment")
	Optional<Comment> findById(@Param("comment") Long id);
}
select
    comment0_.comment_id as comment_1_0_0_,
    post1_.post_id as post_id1_2_1_,
    comment0_.content as content2_0_0_,
    comment0_.post_id as post_id3_0_0_,
    post1_.content as content2_2_1_,
    post1_.title as title3_2_1_ 
from
    comment comment0_ 
inner join
    post post1_ 
        on comment0_.post_id=post1_.post_id 
where
    comment0_.comment_id=?

EntityGraph

  • attributePaths : 페치 조인할 속성을 설정한다.
  • EntityGraph.EntityGraphType
    • FETCH (Default) : 속성으로 지정된 것은 EAGER, 그 외에는 LAZY로 처리된다.
    • LOAD : 속성으로 지정된 것은 EAGER, 그 외에는 엔티티에서 지정된 값, 지정되지 않았다면 기본 FetchType으로 처리된다.
public interface CommentRepository extends JpaRepository<Comment, Long> {

	@EntityGraph(attributePaths = {"post"}, type = EntityGraph.EntityGraphType.LOAD)
	Optional<Comment> findById(Long id);
}
  • JPQL로 했을 때와 차이점은 left outer join이 된다는 점을 명심해야한다. 잘못하다간 원치 않은 값이 나올 수 있다.
select
    comment0_.comment_id as comment_1_0_0_,
    comment0_.content as content2_0_0_,
    comment0_.post_id as post_id3_0_0_,
    post1_.post_id as post_id1_2_1_,
    post1_.content as content2_2_1_,
    post1_.title as title3_2_1_ 
from
    comment comment0_ 
left outer join
    post post1_ 
        on comment0_.post_id=post1_.post_id 
where
    comment0_.comment_id=?

EntityGraphType TEST

@Entity
public class Test {

	@Id
	@GeneratedValue
	private Long id;
}
@Entity
public class Comment {

    ...

    // 추가
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "test_id")
    private Test test;
}

FETCH

  • 기본값
  • 속성으로 지정된 것은 EAGER, 그 외에는 LAZY로 처리된다.
@EntityGraph(attributePaths = {"post"}, type = EntityGraph.EntityGraphType.FETCH)
Optional<Comment> findById(Long id);
select
    comment0_.comment_id as comment_1_0_0_,
    comment0_.content as content2_0_0_,
    comment0_.post_id as post_id3_0_0_,
    comment0_.test_id as test_id4_0_0_,
    post1_.post_id as post_id1_2_1_,
    post1_.content as content2_2_1_,
    post1_.title as title3_2_1_,
    test2_.id as id1_3_2_ 
from
    comment comment0_ 
left outer join
    post post1_ 
        on comment0_.post_id=post1_.post_id 
where
    comment0_.comment_id=?

LOAD

  • 속성으로 지정된 것은 EAGER, 그 외에는 엔티티에서 지정된 값, 지정되지 않았다면 기본 FetchType으로 처리된다.
@EntityGraph(attributePaths = {"post"}, type = EntityGraph.EntityGraphType.LOAD)
Optional<Comment> findById(Long id);
  • Test 엔티티의 fetch 속성은 EAGER이기 때문에 EAGER을 따라간다.
select
    comment0_.comment_id as comment_1_0_0_,
    comment0_.content as content2_0_0_,
    comment0_.post_id as post_id3_0_0_,
    comment0_.test_id as test_id4_0_0_,
    post1_.post_id as post_id1_2_1_,
    post1_.content as content2_2_1_,
    post1_.title as title3_2_1_,
    test2_.id as id1_3_2_ 
from
    comment comment0_ 
left outer join
    post post1_ 
        on comment0_.post_id=post1_.post_id 
left outer join
    test test2_ 
        on comment0_.test_id=test2_.id 
where
    comment0_.comment_id=?