웹 개발 공부 : Back-end/JPA

[JPA 프로젝트 회고 - 6] 지연로딩

Developer KTU 2024. 9. 9. 22:35
반응형

1. 지연로딩

엔티티 조회 시 일반 멤버 변수만 먼저 조회되고, 객체(연관관계 엔티티)로 되어 있는 멤버 변수 조회 시, 가짜 객체로 먼저 조회되고, 실제 멤버 변수가 조회될 때, 실제 쿼리를 한번 더 실행시키는 기법이다.

 

말이 좀 어려운데, 간단한 코드로 보면

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member{
    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String name;
    private int age;
    
    // 연관관계 엔티티
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;
    
    // 생성자
    @builder
    public Member(String name, int age, Team team){
        this.name = name;
        this.age = age;
        
        changeTeam(team);
    }
    
    public void changeTeam(Team team){
    	this.team = team;
        // Team 엔티티의 멤버 리스트에 해당 멤버 추가
        team.getMembers.add(this);
    }
    
}
@Entity
@Getter
@NoArgsConstruntor(aceess = AccessLevel.PROTECTED)
public class Team{
    @Id @GeneratedValue
    @Column(name = "team_id")
    private Long id;
    private String name;
    
    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
    
    public void Team(){
        this.name = name;
    }
}

우선, Member 엔티티를 보자,

id, name, age 처럼 일반 멤버변수들은 Member 엔티티 조회 시, 한번에 조회된다. 하지만, Team 객체는 Member 엔티티에서는 가짜 객체이므로 조회 시, null로 조회될 수는 없으니 '...$HibernateProxy$7ffISbXn' 이런 식으로 조회된다. 그 후 실제 Team의 멤버변수를 조회할 때, Team 멤버변수를 조회하는 쿼리가 수행된다.

 

2. Junit 테스트 코드

@SpringBootTest
@Transactional
class LazyTest{

    @AutoWired
    EntityManager em;
    
    private final MemberRepository memberRepository;
    private final TeamRepository teamRepository;
    
    // 생성자 주입
    public LazyTest(MemberRepository memberRepository
                  , TeamRepository teamRepository){
        this.memberRepository = memberRepository;
        this.teamRepository = teamRepository;
    }
    
    @Test
    public void FetchLazyTest(){
        Team manCity = new Team("manchesterCity");
        teamRepository.save(manCity);
        
        Member member1 = Member.builder()
                               .name("KDB")
                               .age(34)
                               .team(manCity)
                               .build();
        memberRepository.save(member1);
        
        // Rollback은 진행하지만 Insert 쿼리 수행 시 명시
        em.flush();
        
        // Member 엔티티 조회
        Member findMember = memberRepository.findMember(1, "KDB");
        
        // 일반 멤버변수는 한번에 조회됨.
        System.out.println(findMember.getName());	// KDB
        
        // ...$HibernateProxy$7ffISbXn 이런식으로 가짜 객체가 출력됨
        System.out.println(findMember.getTeam().getClass());
        
        // 가짜객체였다가 이때 실제 team의 name을 조회하는 쿼리가 수행됨.
        String teamName = findMember.getTeam().getName();
        assertThat(teamName).isEqualTo("manchesterCity"); 	// true
    }
}

 

 

 

 

다음 포스팅은, N + 1 문제를 포스팅해보겠다.

반응형