[JPA] @EntityGraph란?

BlackBean99·2022년 8월 29일
1

JPA

목록 보기
3/3
post-thumbnail

@EntityGraph 란?

기존에 LAZY Loadgin을 하게 되면 쿼리 실행 시 select 되지 않고 proxy 객체를 만들어 엔티티가
적용시키는데, 프록시 객체를 호출할 떄마다 select 쿼리가 실행한다.

여러 테이블을 한번에 가져와야 하는 경우 LAZY 패치타입으로 가져와서 해결하는 경우가 있다. 하지만, 일부 상황에서 한번에 FetchJoin 을 해야하는 경우가 있다.

이를 하는 과정에서, JPQL이나 QueryDSL 에서 자체 튜닝한 쿼리를 직접 작성해야 하는 번거로움이 있는데 이를 해결해주기 위해서 사용하는 것입니다!

한마디로 정의하면? Spring Data JPA 에서 fetch 조인을 할 때, 어노테이션으로 사용할 수 있는겁니다.

거두절미하고 코드부터 보시죠!

Post

@Entity
@Getter
@NoArgsConstructor
public class Post {
    @Id
    @GeneratedValue
    private Long id;

    private String title;

    public Post(String title){
        this.title = title;
    }
}

PostRepository

public interface PostRepository extends JpaRepository<Post, Long> {
    @Override
    @EntityGraph("Post.fetchPost")
    Optional<Post> findById(Long id);
}

Repository에 내가 같이 fetch Join을 할 함수 위에 EntityGraph 를 선언해주면 됩니다.

Comment

@Entity
@Getter
@NoArgsConstructor
@NamedEntityGraph(name="Comment.fetchPost", attributeNodes = @NamedAttributeNode("post"))
public class Comment {
    @Id
    @GeneratedValue
    private Long id;

    private String comment;

    @ManyToOne
    private Post post;

    public Comment(String comment, Post post){
        this.comment = comment;
        this.post = post;
    }
}

연결시킬 테이블을 NamedEntityGraph 를 선언해서 post와 연결시킵니다.
현 테이블을 정의시키는 name 속성와 연결시킬 attributeNodes = @NamedAttributeNode 이 있습니다.

CommentRepository

public interface CommentRepository extends JpaRepository<Comment,Long> {
    @EntityGraph("Comment.fetchPost")
    List<Comment> findByComment(String title);

    @EntityGraph("Comment.fetchPost")
    Optional<Comment> findById(Long id);

    @EntityGraph("Comment.fetchPost")
    Comment findOneByComment(String title);
}

이 동작들을 해볼 테스트 코드를 작성해보면

TestCode

@DataJpaTest
public class queryTest {
    @Autowired
    PostRepository postRepository;

    @Autowired
    CommentRepository commentRepository;
    @AfterEach
    public void cleanup(){
        postRepository.deleteAll();
    }

    @Test
    public void PostRepositoryTest(){
        Post p1 = new Post("p1");
        Post p2 = new Post("p2");

        postRepository.save(p1);
        postRepository.save(p2);

        postRepository.flush();

        Comment c1 = new Comment("c1",p1);
        Comment c2 = new Comment("b",p2);

        Comment save = commentRepository.save(c1);
        commentRepository.save(c2);

        commentRepository.flush();
        System.out.println("======================OneByComment====================");
        List<Comment> comments = commentRepository.findByComment("b");
        System.out.println(comments.size() == 2);


        System.out.println("======================OneByComment====================");
        Comment comment = commentRepository.findOneByComment("b");
        System.out.println(comment != null);
    }
}

아래 실행된 find 쿼리를 hibernate로 확인해보면,

이렇게 post 를 left outer join을 통해서 같이 조회를 합니다.

특정 상황에 계속 LAZY 로딩을 세팅하는 것보다는 이 방법이 좋을 수도 있겠네요 ㅎㅎ

쿼리 최적화는 정말 방법이 참 많은 것 같습니다. 다른 최적화 방법을 찾아서 더 포스팅 해보겠습니다.

profile
like_learning

0개의 댓글