지연 로딩과 즉시 로딩

금은체리·2023년 11월 18일
1

Spring

목록 보기
33/49

지연 로딩과 즉시 로딩

  • 음식 테이블과 고객 테이블이 N : 1 양방향 관계라 가정
@Test
@DisplayName("아보카도 피자 조회")
void test1() {
    Food food = foodRepository.findById(2L).orElseThrow(NullPointerException::new);

    System.out.println("food.getName() = " + food.getName());
    System.out.println("food.getPrice() = " + food.getPrice());

    System.out.println("아보카도 피자를 주문한 회원 정보 조회");
    System.out.println("food.getUser().getName() = " + food.getUser().getName());
}

  • "아보카도 피자"의 가격을 조회하려고 했을 뿐인데 자동으로 JOIN문을 사용하여 연관관계가 설정되어 있는 고객 테이블의 정보도 가져옴


  • JPA는 연관관계가 설정된 Entity의 정보를 바로 가져올지, 필요할 때 가져올 지 정할 수 있음
    • 즉, 가져오는 방법을 정하게 됨 = JPA 에서는 Fetch Type이라 부름
    • Fetch Type의 종류
      • LAZY : 지연 로딩 으로 필요한 시점에 정보를 가져옴
      • EAGER : 즉시 로딩 으로 이름의 뜻처럼 조회할 때 연관된 모든 Entity의 정보를 즉시 가져옴
  • 기본적으로 @OneToMany 애너테이션은 Fetch Type의 default 값이 LAZY 로 지정되어 있고
  • 반대로 @ManyToOne 애너테이션은 EAGER 로 되어 있음
  • 다른 연관관계 애너테이션들도 default 값이 있는데 이를 구분하는 방법 존재
    • 애너테이션 이름에서 뒤쪽에 Many가 붙어있으면 설정된 해당 필드가 Java 컬렉션 타입
      • 즉, 해당 Entity의 정보가 여러 개 들어있을 수있음
      • 따라서 효율적으로 정보를 조회하기 위해 지연 로딩 이 default로 설정되어 있음
    • 반대로 이름 뒤쪽이 One일 경우 해당 Entity 정보가 한 개만 들어오기 때문에 즉시 정보를 가져와도 무리가 없어 즉시 로딩 이 default로 설정되어 있음
@Test
@Transactional
@DisplayName("Robbie 고객 조회")
void test2() {
    User user = userRepository.findByName("Robbie");
    System.out.println("user.getName() = " + user.getName());

    System.out.println("Robbie가 주문한 음식 이름 조회");
    for (Food food : user.getFoodList()) {
        System.out.println(food.getName());
    }
}

  • 이번에는 Robbie 고객을 조회한 후 Robbie 고객이 주문한 음식들의 이름을 조회함
  • @OneToMany 즉, defaul가 지연 로딩 으로 설정되어있기 때문에 우선 고객을 조회한 후
  • user.getFoodList() 호출 즉, 주문한 음식의 정보가 필요한 시점에 음식 테이블에 해당 고객 Entity의 식별자 값을 사용하여 Select SQL이 수행됨

영속성 컨텍스트와 지연 로딩

  • JPA 기초 강의에서 공부 한 영속성 컨텍스트

    • 1차 캐시
    • 쓰기 지연 저장소
    • 변경 감지
  • 지연 로딩도 마찬가지로 영속성 컨텍스트의 기능 중 하나

    • 따라서 지연 로딩된 Entity의 정보를 조회하려고 할 때는 반드시 영속성 컨텍스트가 존재 해야함
    • '영속성 컨텍스트가 존재해야한다'라는 의미는 결국 '트랜잭션이 적용되어있어야 한다'라는 의미와 동일
    @Test
    @DisplayName("Robbie 고객 조회 실패")
    void test3() {
        User user = userRepository.findByName("Robbie");
        System.out.println("user.getName() = " + user.getName());
    
        System.out.println("Robbie가 주문한 음식 이름 조회");
        for (Food food : user.getFoodList()) {
            System.out.println(food.getName());
        }
    }

    • 'Robbie 고객 조회 실패' 테스트 코드를 확인해보면 @Transactional이 test3() 메서드에 설정되어있지 않음
    • 즉, 트랜잭션이 적용되지 않았기 때문에 지연 로딩 된 음식 Entity 정보들을 user.getFoodList() 즉, 필요한 시점에 조회하려고 하자 오류가 발생함
    • 따라서 지연 로딩 된 정보를 조회하려고 할 때는 반드시 트랜잭션이 적용되어 영속성 컨텍스트가 존재하는지 확인 해야함
profile
전 체리 알러지가 있어요!

0개의 댓글