지연로딩
지연로딩(Lazy Loading)은 객체가 실제 사용될 때까지 데이터베이스에서 데이터를 불러오지 않고, 필요한 순간에 데이터를 불러옵니다. 즉, 지연로딩을 사용하면 객체 그래프를 탐색하면서 연관된 객체를 가져오지 않고, 실제로 해당 객체가 사용될 때 가져오게 됩니다.
지연로딩은 즉시로딩(Eager Loading)과 반대되는 개념입니다. 즉시로딩은 객체 그래프를 탐색하는 시점에 연관된 객체를 미리 불러오므로, 일부 데이터를 미리 가져올 수 있어 성능상 이점이 있을 수 있지만, 데이터를 불필요하게 가져오는 경우가 있습니다.
주의
지연로딩을 사용하면 영속성 컨텍스트가 종료된 이후에도 데이터베이스에서 데이터를 가져올 수 있다는 점입니다. 따라서 지연로딩을 사용할 때는 프록시 객체를 사용하여 실제 객체를 사용하는 시점까지 데이터베이스 연결을 지연시키는 것이 좋습니다.
프록시 객체란 실제 객체 대신 사용되는 가짜 객체입니다. 프록시 객체는 실제 객체와 같은 인터페이스를 구현하며, 같은 메서드를 가지고 있습니다. 프록시 객체는 실제 객체를 대신하여 사용될 수 있으며, 실제 객체를 사용하는 시점에 데이터베이스에서 데이터를 불러옵니다.
지연로딩을 통한 프록시 조회
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.LAZY) //**
@JoinColumn(name = "TEAM_ID")
private Team team;
}
Java
복사
•
처음 em.find를 통해 엔티티를 가지고 오면 Proxy 객체로 생성
•
실제 team을 사용하는 시점에 초기화(DB 조회)
Member member = em.find(Member.class, 1L);
Java
복사
Team team = member.getTeam();
team.getName();
Java
복사
주의!!!
•
가급적 지연 로딩만 사용(특히 실무에서)
•
즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
•
즉시 로딩은 JPQL에서 N+1 문제를 일으킨다. → 쿼리가 한번 더 나간다는 뜻
•
@ManyToOne, @OneToOne은 기본이 즉시 로딩
> LAZY로 설정
•
@OneToMany, @ManyToMany는 기본이 지연 로딩
즉시 로딩 EAGER를 사용해서 함께 조회
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.EAGER) //**
@JoinColumn(name = "TEAM_ID")
private Team team;
}
Java
복사
•
JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회
•
일반적으로 그냥 Join을 이용해 함께 바로 객체를 가지고 옴
실무에서 사용시
•
모든 연관관계에 지연 로딩을 사용해라!
실무에서 즉시 로딩을 사용하지 마라!
•
JPQL fetch 조인이나, 엔티티 그래프 기능을 사용해라!(뒤에서 설명)
◦
우선 모두 지연로딩 적용 후 함께 가지고 오고 싶을 때 사용하는 join fetch
List<Member> members = em.createQuery("select m from Member m join fetch m.team", Member.class)
Java
복사
•
즉시 로딩은 상상하지 못한 쿼리가 나간다.