즉시로딩(Eager Loading)과 지연로딩(Lazy Loading)

kmb·2023년 6월 3일
0

JPA

목록 보기
4/7
post-thumbnail

즉시로딩(Eager Loading) vs 지연로딩(Lazy Loading)

 
Spring Data JPA에서 @XXXToOne으로 연관관계가 설정되어 있는경우
기본적으로 즉시로딩(Eager Loading)으로 처리하게 됩니다.

이는 불필요한 join 쿼리가 포함되기 때문에 지연로딩(Lazy Loading)의 사용이 권장됩니다.
(단 @XXXToMany는 기본적으로 지연로딩(Lazy Loading))

지연로딩(Lazy Loading)은 객체의 초기화를 지연시켜 로딩하는 방법으로써 실제 객체 대신 프록시 객체를 로딩 해두고 해당 객체를 실제 사용할 때만(ex. getter 메서드를 사용할 때) 영속성 컨텍스트를 통해 실체 객체를 호출하는 로딩입니다.


  • 즉시로딩(Eager Loading) 예시

 
Member엔티티와 Team엔티티는 N대1 관계

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(exclude = "team")
@Table(name = "members")
public class Member extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    @Column
    private String memberName;

    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;

    @Builder
    public Member(Long id, String memberName, Team team) {
        this.id = id;
        this.memberName = memberName;
        this.team = team;
    }
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@Table(name = "teams")
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "team_id")
    private Long id;

    @Column
    private String teamName;

    @Builder
    public Team(Long id, String teamName) {
        this.id = id;
        this.teamName = teamName;
    }
}

 
테스트 코드에서 확인

@SpringBootTest
@Log4j2
class MemberTest {

    @Autowired private MemberRepository memberRepository;
    @Autowired private TeamRepository teamRepository;

    private Member member1, member2;

    @BeforeEach
    void setup() {

        Team team = Team.builder()
                .id(1L)
                .teamName("team")
                .build();

        teamRepository.save(team);

        member1 = Member.builder()
                .id(1L)
                .memberName("member1")
                .team(team)
                .build();

        member2 = Member.builder()
                .id(2L)
                .memberName("member2")
                .team(team)
                .build();
    }

    @Test
    @DisplayName("eager loading test")
    void test() {

        // given
        memberRepository.save(member1);

        // when
        Member member = memberRepository.findById(1L)
                .orElseThrow(() -> new IllegalArgumentException("멤버가 없습니다"));

        // then
        log.info("member : {}", member);
    }
}

기본적으로 즉시로딩인 Member를 조회하는 쿼리를 보면
Member 테이블 외에도 Team 테이블도 함께 left outer join을 사용하여 조회되고 있음이 확인됩니다.

 
따라서 @XXXToOne 어노테이션에 지연로딩인 (fetch = FetchType.LAZY)를 추가한다음

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(exclude = "team")
@Table(name = "members")
public class Member extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    @Column
    private String memberName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;

    @Builder
    public Member(Long id, String memberName, Team team) {
        this.id = id;
        this.memberName = memberName;
        this.team = team;
    }
}

 
다시 테스트코드에서 확인해보면Member테이블만 조회되는것이 확인됩니다.

profile
꾸준하게

0개의 댓글