본문 바로가기
Spring/JPA

[JPA] fetch join 적용하기

by 델버 2023. 1. 19.
  • 게시판 프로젝트에서 홈을 요청하면 게시글 리스트를 불러온다. 문제는 쿼리인데, 페이징 할 때마다 쿼리가 3개가 나간다
    1. select 게시글
    2. select 회원: 닉네임 조회
    3. 게시글 count: 페이징 뷰게시판 프로젝트에서 홈 화면에서 게시글을 불러온다. 문제는 쿼리인데, 페이징 할 때마다 쿼리가 3개가 나간다.
  • 김영한님의 JPA 강의에서 들은 fetch join을 적용해보려 한다.

fetch join

  • 여러 엔티티를 한 번의 SQL로 가져오는 것이다.
  • 내 상황에서는 게시글을 불러오고 회원을 불러왔는데 이제 한 번에 fetch join으로 가져온다는 것이다. 이렇게 되면 쿼리 한 번에 회원이 영속성 컨테스트에 처음부터 들어있기 때문에 성능 최적화에 좋다.
  • JPQL과 나가는 SQL 쿼리는 이렇다.
    • JPQL: select p from Post p join fetch p.member;
    • SQL: select p.\*, m.\* from Post p inner join Member m on p.member\_id = m.id

적용 전

@RequiredArgsConstructor
@Repository
public class PostRepository {

    private final EntityManager em;

    public Long save(Post post) {
        em.persist(post);
        return post.getId();
    }

    public Post findById(Long postId) {
        return em.find(Post.class, postId);
    }

    public List<Post> findAll() {
        return em.createQuery("select p from Post p", Post.class)
                .getResultList();
    }

    public List<Post> findPage(int offset, int limit) {
        return em.createQuery("select p from Post p order by p.createDate DESC", Post.class)
                .setFirstResult(offset)
                .setMaxResults(limit)
                .getResultList();
    }

    public Long countPost() {
        return em.createQuery("select count(p) from Post p", Long.class)
                .getSingleResult();
    }

    public void delete(Post post) {
        em.remove(post);
    }

}
  • 내 게시판에서는 게시글을 조회하는 곳이면 회원을 조회하게 되어있다. 그래서 쿼리가 2개씩 나가게 되는데 이를 fetch join을 사용하여 줄이려 한다.

적용 후

@RequiredArgsConstructor
@Repository
public class PostRepository {

    private final EntityManager em;

    public Long save(Post post) {
        em.persist(post);
        return post.getId();
    }

    public Optional<Post> findById(Long postId) {
        return em.createQuery("select p from Post p" +
                        " join fetch p.member where p.id = :postId", Post.class)
                .setParameter("postId", postId)
                .getResultList().stream().findFirst();

    }

    public List<Post> findAll() {
        return em.createQuery("select p from Post p", Post.class)
                .getResultList();
    }

    public List<Post> findPage(int offset, int limit) {
        return em.createQuery("select p from Post p" +
                        " join fetch p.member " +
                        " order by p.createDate DESC", Post.class)
                .setFirstResult(offset)
                .setMaxResults(limit)
                .getResultList();
    }

    public Long countPost() {
        return em.createQuery("select count(p) from Post p", Long.class)
                .getSingleResult();
    }

    public void delete(Post post) {
        em.remove(post);
    }

}
  • select p from Post p join fetch p.member 를 이용해 게시글을 가져올 때 한 번에 쿼리로 회원의 엔티티까지 가져오게 되었다.
Hibernate: select p1_0.post_id,p1_0.category,p1_0.content,p1_0.create_date,m1_0.member_id,m1_0.email,m1_0.join_date,m1_0.join_root,m1_0.password,m1_0.role,m1_0.user_name,p1_0.title from posts p1_0 join member m1_0 on m1_0.member_id=p1_0.member_id where p1_0.post_id=?

 

댓글