DB/JPA
[JPA] 즉시 로딩과 지연 로딩
동그리담
2025. 2. 22. 16:26
Member와 Team에 연관 관계가 있다고 가정할 떄,
1. 비지니스 로직에서 Member만 자주 쓰이는 경우 Member를 가져올 때, Team까지 조인해서 가져와야 할까?
지연 로딩을 사용해서, Team을 프록시 객체로 가져올 수 있다.
fetch = FetchType.LAZY
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long id;
private String username;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
public Team getTeam(){
return this.team;
}
}
public static void main(){
Team team = member.getTeam() //프록시 초기화 안됌
teamName = team.getTeam() //프록시 초기화
}
2. 비지니스 로직에서 Member와 Team까지 같이 쓰일 때 LAZY 로딩을 하게 되면 쿼리가 2번 날아가게 된다.
즉시 로딩을 사용해서, 매번 같이 가져올 수 있다.
fetch = FetchType.EAGER (Default: @ManyToOne, @OneToOne)
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long id;
private String username;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id")
private Team team;
public Team getTeam(){
return this.team;
}
}
대부분의 JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회하도록 되어있다.
프록시와 즉시로딩 주의
- 가급적 지연 로딩만 사용
- 즉시 로딩을 적용하면 예상치 못한 SQL이 발생한다.
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
- @ManyToOne, @OneToOne의 경우 EAGER가 Default이다. (LAZY로 설정)
- @OneToMany, @ManyToMany는 기본이 지연 로딩
- 즉시 로딩 처럼 사용 가능한 해결 법 (1+1 로 가져오기)
- 모든 연관관계를 LAZY Loading으로 사용하고 둘 다 필요한 시점에 JPQL에서 join fetch 사용
- em.createQuery("select m from Member m join fetch m.team", Member.class)
- @entitygraph 애너테이션 사용
- BatchSize
- 모든 연관관계를 LAZY Loading으로 사용하고 둘 다 필요한 시점에 JPQL에서 join fetch 사용
// 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
public static void main(){
List<Member> members = em.createQuery("select m from Member m", Member.class)
.getResultList();
/*
SQL => select * from member
가져오고 보니 EAGER로 설정 돼있으면?
SQL => select from * team where team_id = :team_id
쿼리가 한 번 더 나가게 됌
각기 팀이 다르다면? N만큼 쿼리가 나가게됌
*/
}
출처 관련 : https://tan-sog.tistory.com/90