연관관계 있는 엔터티를 조회하게 될 경우 fetch = FetchType.LAZY 처럼 LAZY로 지연로딩 설정이 되어있을 때 , 해당 엔터티(Member)만 조회하고 연관관계 있는 엔터티(Team)를 조하지 않게 된다.
이 때 Team에 대한 정보가 필요하게 될 때 Team에 대한 정보를 조회해야 하는데, 이런 상황에서 실행시킨 쿼리 외(실행시킨 쿼리는 Member에 대한 쿼리)에도 쿼리가 추가로 나가기 때문에 n+1 문제가 발생한다.
좀 더 쉽게 말해서, Member 쿼리 실행 시 연관관계 있는 Team의 경우 select 되지 않고 proxy 객체를 만들어 가상의 엔티티를 반환한다. 그 후 해당 프시 객체를 호출할 때마다 그때그때 select 쿼리가 실행된다.
@EntityGraph는 Data JPA에서 EAGER 로딩이 필요한 경우에만 어노테이션을 통해 적용시킬 수 있도록 만들어 준 기능이다.
<Entity>
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
}
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members;
}
<Repository>
public interface MemberRepository extends JpaRepository<Member, Long> {
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
@EntityGraph(attributePaths = {"team"})
Member findByName(String name);
}
-Team과 Member는 일대다 관계
이 예시에서 @EntityGraph의 사용은 다음과 같은 의미를 갖습니다:
- findAll() 메서드: 모든 Member를 조회할 때, 각 Member의 Team 정보도 함께 조회합니다.
- findByName(String name) 메서드: 이름으로 Member를 조회할 때, 해당 Member의 Team 정보도 함께 조회합니다.
@EntityGraph를 사용하지 않았다면, LAZY 로딩으로 인해 Team 정보를 필요로 할 때마다 추가 쿼리가 발생했을 것이다.
>> 이는 N+1 문제를 유발할 수 있다.
예를 들어, 모든 Member의 이름과 소속 Team의 이름을 출력하는 코드를 작성한다고 가정해 보면
List<Member> members = memberRepository.findAll();
for (Member member : members) {
System.out.println("Member: " + member.getName() + ", Team: " + member.getTeam().getName());
}
@EntityGraph를 사용하지 않았다면:
- 모든 Member를 조회하는 쿼리 1번
- 각 Member의 Team을 조회하는 쿼리 N번 (N+1문제) 발생한다.
하지만 @EntityGraph를 사용하면:
- Member와 Team을 함께 조회하는 쿼리 1번으로 모든 정보를 가져올 수 있다.
이렇게 @EntityGraph를 사용하면 필요한 연관 엔티티를 효율적으로 함께 조회할 수 있어, 애플리케이션의 성능을 크게 향상시킬 수 있습니다.
'Spring > Spring Data JPA' 카테고리의 다른 글
| Spring Data JPA - 사용자 정의 메서드 (1) | 2024.06.30 |
|---|---|
| Spring 입문(김영한, 인프런) - 스프링 데이터 jpa (0) | 2023.12.27 |
| Spring 입문(김영한, 백엔드) - jpa (1) | 2023.12.27 |