앞선 포스팅에서 프록시에 대해 알아보았습니다. 이번 포스팅에서는 JPA에서 프록시를 어떻게 활용하는지, 즉시 로딩과 지연 로딩을 통해 알아봅니다.
지연 로딩 (Lazy Loading)
1
2
3
4
5
6
7
8
9
|
@Entity
public class Member
{
@Id @GeneratedValue
private Long id;
@ManyToOne(fetch=FetchType.LAZY)
private Team team;
}
|
cs |
지연 로딩은 엔티티 조회 시점이 아닌 엔티티 내 연관관계를 참조할 때 해당 연관관계에 대한 SQL이 질의되는 기능이며, fetch=FetchType.LAZY 옵션으로 지정할 수 있습니다.
엔티티 조회 시, 연관관계 필드는 프록시 객체로 제공됩니다.
1
2
3
4
5
6
7
|
Member findMember = EntityManager.find(Member.class, 1L);
member.getTeam(); // 프록시 객체 초기화 X
member.getTeam().getClass(); // 프록시 객체
member.getTeam().getName(); // 프록시 객체 초기화 및 SQL 질의
|
cs |
위 코드와 같이 지연로딩되는 연관관계를 참조하기 전까지는 프록시 객체가 초기화되지 않고, 프록시 객체를 참조할 때 프록시 객체가 초기화되고 SQL이 질의됩니다.
즉시 로딩
1
2
3
4
5
6
7
8
9
|
@Entity
public class Member
{
@Id @GeneratedVaule
private Long id;
@ManyToOne(fetch=FetchType.EAGER)
private Team team;
}
|
cs |
즉시 로딩은 엔티티 조회 시 연관관계에 있는 데이터까지 한 번에 조회해오는 기능이며, fetch=FetchType.EAGER 옵션으로 지정할 수 있습니다.
즉시 로딩으로 조회된 엔티티의 연관관계 필드에는 실제 엔티티 객체가 반환됩니다.
주의사항
위 내용까지 봤을때는 즉시 로딩이 매력적일 수 있습니다. 하지만 반드시 알아야 할 내용이 있습니다.
- 실무에서는 가급적 지연 로딩만 사용합니다.
- 즉시 로딩을 사용하면 예상하지 못한 SQL이 발생할 수 있기 때문입니다.
예) 다른 개발자가 Member를 조회할 때는 Team이 조회될거라고 생각하지는 못하겠죠? - 즉시 로딩은 JPQL 사용 시 N+1 문제를 유발합니다.
예를 들어, JPQL로 전체 Member 목록을 조회하면 아래와 같은 코드가 작성됩니다.
1List<Member> members = EntityManager.createQuery("select m from Member m", Member.class);cs
그리고 이 JPQL이 수행되면 실제로는 SELECT 쿼리가 총 2회 발생합니다.(MEMBER, TEAM 각각 1회)
JPQL이 EntityManager.find 메서드와 동작하는 방식이 달라서 발생하는 문제인데, JPQL에서 매개변수로 넘어온 쿼리문을 실행하고 나서 확인하니, team이 즉시 로딩이어서 다시 TEAM 테이블에 SELECT 쿼리를 질의하게 되는 것입니다.
따라서, Member 엔티티에서 사용하는 즉시 로딩이 많으면 많아질수록 추가적인 SELECT 질의는 증가할 것이고, 결국 Member만 조회했는데 N+1 개의 쿼리 질의가 발생하는 거죠. - 연관관계별로 fetch 옵션의 기본값이 다릅니다.
- @ManyToOne : EAGER
- @OneToOne : EAGER
- @ManyToMany : LAZY
- @OneToMany : LAZY
즉시 로딩의 위험성을 알고 모든 연관관계를 지연 로딩으로 교체했다고 가정했을 때, 특정 비즈니스 로직에서 Member와 Team을 동시에 조회해야 하는 경우에는 어떻게 해야 할까요?
▶ 이후에 다룰 JPQL의 패치 조인을 사용해 조회하면 됩니다.
출처 :: 인프런 강의(자바 ORM 표준 JPA 프로그래밍 - 기본편)
반응형
'🌱 SPRING > JPA' 카테고리의 다른 글
[QueryDSL] JPA에서 MySQL 비트연산하는 방법 (0) | 2022.07.15 |
---|---|
[Spring Data JPA] Auditing에 ZonedDateTime 사용하기 (0) | 2021.05.27 |
[JPA] 프록시 (1) | 2020.07.29 |
[JPA] 상속관계 매핑 (0) | 2020.07.19 |
[JPA] 다양한 연관관계 매핑 (0) | 2020.07.19 |