[Spring Boot] 36. 스프링부트 블로그 v2 (JPA) (6) 게시글 목록(1) - EAGER/LAZY

김주희's avatar
Apr 06, 2025
[Spring Boot] 36. 스프링부트 블로그 v2 (JPA) (6) 게시글 목록(1) - EAGER/LAZY
BoardRepository에서 JPQL로 만들면 쿼리가 어떻게 발생하는지 알아보자!
필기
유효성 검사 - onsubmit JPA 게시글 목록에서 User 테이블 필요 board를 조회할때 jpa를 사용하면 board 조회 시 user도 join한다. eager = object relation mapping 해 -> join 안하고 select 3번 -> 게시글 쓴 사람이 1번이므로 -> PC에서 캐싱했기 때문에 원래는 user_id를 select로 4번 해야하지만 1번 게시글을 select 하면 lazy =orm 하지마 board 데이터 4건 -> findAll Board 클래스에 Object Mapping 근데 전략이 eager이면 board에 user_id를 넣는 곳이 없음 -> 객체를 넣어야함 user tb를 조회해서 relation mapping -> 이게 4번 일어나야 하는데 3번뿐 = eager (근데 쿼리 한번에 i/o이므로 데이터 건수가 많으면 곤란 (n+1 : 연관된 애들 전부 select?) join해서 넣는 경우 - 이것도 relation mapping에 eager 전략 근데 둘중 어떤 방법 선택했는지는 확인해봐야 알 수 있음 Board에서 User객체는 join해서 바로 넣어주기/ select해서 4번 relation된 객체에 값을 넣어주면 eager이다 -> User 값을 안넣어주면 lazy lazy일때 - Board의 User에는 조회하는게 아니라 fk인 id=1만 존재 (tb에서 가져온 user_id) => boardList.get(0).getUser()까지는 안터짐 // Lazy -> // Eager -> // Eager -> => 근데 게시글 목록에 당장 user 정보 필요 없으므로 relation mapping을 안하는 lazy 전략을 쓴다! -> eager로 하면 쓸데없는 정보를 조회하게 될 수 있으므로 lazy로 하고 relation mapping이 필요하면 직접 join하는게 낫다. -> 무조건 lazy 전략을 쓴다. 서버 사이드 렌더링 서버에서 html화면에 데이터를 붙여서 오는 기술 CSR - 클라이언트 측 언어로 57:00 서버사이드렌더링 모델(request 객체)에 pw같은 보안에 민감한 데이터 줘도 괜찮다 -> 서버에서 request에 담아뒀다가 html화면에 안뿌리면 되기 때문 -> DTO로 데이터를 전달하게 될 경우에는 안된다!

1. Board 조회시 User도 같이 조회될까?

0. Board 클래스

  1. User는 FetchType을 EAGER으로 설정한다.
notion image
 

1. BoardRepository

public List<Board> findAll() { Query query = em.createQuery("select b from Board b order by b.id desc", Board.class); return query.getResultList(); }
 

2. BoardRepositoryTest

  1. findAll 메서드를 실행하면 어떤 쿼리가 발생하는지 테스트해보자.
  1. 메서드의 매개변수가 없으므로 given 데이터는 없다.
package shop.mtcoding.blog.board; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; import java.util.List; @Import(BoardRepository.class) // BoardRepository가 메모리(IoC)에 뜬다. @DataJpaTest // EntityManager, PC가 메모리(IoC)에 뜬다. public class BoardRepositoryTest { @Autowired // DI : JUnit에서는 생성자 주입이 불가능하다. private BoardRepository boardRepository; @Test public void findAll_test() { // given -> 함수의 매개변수(e.g. findById에서는 id) // when -> 테스트할 함수 호출 -> 쿼리 확인 List<Board> boardList = boardRepository.findAll(); // eye } }
 

3. 쿼리

  1. Board는 한 번, User는 세 번 조회되는 것을 알 수 있다.
Hibernate: select b1_0.id, b1_0.content, b1_0.created_at, b1_0.is_public, b1_0.title, b1_0.user_id from board_tb b1_0 order by b1_0.id desc Hibernate: select u1_0.id, u1_0.created_at, u1_0.email, u1_0.password, u1_0.username from user_tb u1_0 where u1_0.id=? Hibernate: select u1_0.id, u1_0.created_at, u1_0.email, u1_0.password, u1_0.username from user_tb u1_0 where u1_0.id=? Hibernate: select u1_0.id, u1_0.created_at, u1_0.email, u1_0.password, u1_0.username from user_tb u1_0 where u1_0.id=?
 

4. 더미데이터 - 게시글

notion image
 

5. EAGER

연관관계가 있는 것까지 같이 조회

6. LAZY

연관된 object mapping 안해줌
user의 getter로 조회하면
 

2. Board 조회시 User는 몇 번 조회될까? (Test2)

eager = object relation mapping 해 -> join 안하고 select 3번 -> 게시글 쓴 사람이 1번이므로 -> PC에서 캐싱했기 때문에 원래는 user_id를 select로 4번 해야하지만 1번 게시글을 select 하면 lazy =orm 하지마

1. 더미데이터에서 게시글을 쓴 user_id가 전부 1이라면

  1. 게시글을 조회할 때
notion image
n = 연관된 애들의 (relation) 개수 ⇒ n+1??????
 
notion image
 
 

3. LAZY 전략

1.

  1. 무조건 LAZY 전략으로 간다.
  1. 연관된 객체 조회가 필요하면, 조인쿼리는 직접 작성한다.
 
notion image
 
getter를 호출할때 user가 조회가 된다.
notion image
package shop.mtcoding.blog.board; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; import java.util.List; @Import(BoardRepository.class) // BoardRepository가 메모리(IoC)에 뜬다. @DataJpaTest // EntityManager, PC가 메모리(IoC)에 뜬다. public class BoardRepositoryTest { @Autowired // DI : JUnit에서는 생성자 주입이 불가능하다. private BoardRepository boardRepository; @Test public void findAll_test() { // given -> 함수의 매개변수(e.g. findById에서는 id) // when -> 테스트할 함수 호출 -> 쿼리 확인 List<Board> boardList = boardRepository.findAll(); // Lazy -> Board -> User(id=1) // Eager -> N+1 -> Board조회 -> 연관된 User 유저 수 만큼 주회 // Eager -> Join -> 한방쿼리 System.out.println("--------------------"); boardList.get(0).getUser().getUsername(); System.out.println("--------------------"); // eye } }
 
board 데이터 4건 -> findAll Board 클래스에 Object Mapping 근데 전략이 eager이면 board에 user_id를 넣는 곳이 없음 -> 객체를 넣어야함 user tb를 조회해서 relation mapping -> 이게 4번 일어나야 하는데 3번뿐 = eager (근데 쿼리 한번에 i/o이므로 데이터 건수가 많으면 곤란 (n+1 : 연관된 애들 전부 select?) join해서 넣는 경우 - 이것도 relation mapping에 eager 전략 근데 둘중 어떤 방법 선택했는지는 확인해봐야 알 수 있음 Board에서 User객체는 join해서 바로 넣어주기/ select해서 4번 relation된 객체에 값을 넣어주면 eager이다 -> User 값을 안넣어주면 lazy lazy일때 - Board의 User에는 조회하는게 아니라 fk인 id=1만 존재 (tb에서 가져온 user_id) => boardList.get(0).getUser()까지는 안터짐 // Lazy -> // Eager -> // Eager -> => 근데 게시글 목록에 당장 user 정보 필요 없으므로 relation mapping을 안하는 lazy 전략을 쓴다! -> eager로 하면 쓸데없는 정보를 조회하게 될 수 있으므로 lazy로 하고 relation mapping이 필요하면 직접 join하는게 낫다. -> 무조건 lazy 전략을 쓴다.
sout으로 찍어보면 love가 조회된다.
sout으로 찍어보면 love가 조회된다.
 
 
Share article

jay0628