본문 바로가기

Development/DB, JPA

지연로딩과 즉시로딩

다음과 같은 엔티티 관계가 있다고 하자 

Member : Team = N : 1 


Member Entity

@Getter
@Setter
@Entity
public class Member {

@Column(name = "memberName")
private String memberName;

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

Team Entity

@Getter
@Setter
@Entity
public class Team {

@Column(name = "teamId")
private String teamId;
}


즉시 로딩 : 엔티티 조회 시 연관된 엔티티도 함께 조회.

@ManyToOne(fetch = FetchType.EAGER) // 또는 defualt 설정이다
@JoinColumn(name = "teamId")
private Team team;

즉, Member member = em.find(Member.class, "member1") ; 을 실행하게 되면 

member에 매핑된 Team도 함께 조회 된다.(즉시 로딩을 최적화 하기 위해여 가능하면 조인쿼리가 날아간다)

member 1 로딩과 동시에 team1도 즉시 로딩(Eager)


지연 로딩 : 엔티티를 실제 사용 할때 조회.

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

Member member = em.find(Member.class, "member1") ; 을 실행하게 되면

member 정보만 로딩하고, member에 매핑된 team의 정보는 로딩하지 않는다. 대신 프록시 객체를 넣어둔다.

Team team = member.getTeam(); 을 통해서 반환되는 프록시 객체는 실제 사용될 때까지 데이타 로딩을 미룬다.

team.getName(); 등과 같이 실제로 사용는 구문이 나오면 DB select 쿼리가 날아가서 프록시 객체를 초기화 한다.


JPA의 기본 Fetch 전략은 다음과 같다.

@ManyToOne, @OneToOne :  FetchType.EAGER

@OneToMany, @ManyToMany : FetchType.LAZY


처음부터 연관된 엔티티들을 모두 영속성 컨텍스트에 올려두는 것은 비효율 적이다. 그렇다고해서 필요할때마다 sql 을 실행하는 것도 최적화 측면에서 좋지 않다.

애플리케이션의 성향에 따라 즉시로딩 또는 지연로딩을 알맞게 사용하는 것이 좋다.

읽고 있는 JPA책에서는 우선 모든 Fetch를 Lazy로 수행하며, 애플리케이션의 상황을보며 EAGER로 전환할 수 있는 부분을 찾는게 좋을 것이라고 한다.