JPA의 FetchJoin을 이해해야 @EntityGraph를 이해할 수 있다.
JPA에서 FetchJoin 중요!
Spring Data JPA에서 @EntityGraph를 사용하여 쉽게 해결할 수 있다.
Member 클레스
... 생략
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY) // ManyToOne은 fetchType.LAZY (지연로딩)설정 -> 후에 성능 최적화
@JoinColumn(name = "team_id")
private Team team;
... 생략
}
지연 로딩 : Member를 부르면 Team team; 을 부르지 않고 프록시(가짜 객체)로 채워 넣고 있다가 team의 데이터를 실제로 사용하는 시점에 쿼리가 호출된다.
테스트 코드
@Test
public void findMemberLazy() throws Exception {
//given
//member1 -> teamA
//member2 -> teamB
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
teamRepository.save(teamA);
teamRepository.save(teamB);
memberRepository.save(new Member("member1", 10, teamA));
memberRepository.save(new Member("member2", 20, teamB));
em.flush();
em.clear();
//when
List<Member> members = memberRepository.findAll();
//then
for (Member member : members) {
System.out.println("member.getUsername() = " + member.getUsername());
System.out.println("member.getTeam().getClass() = " + member.getTeam().getClass());
System.out.println("member.getTeam().getName() = " + member.getTeam().getName());
}
}
teamName을 부르려는 데 없으니 team 쿼리를 호출한 후 3번처럼 team의 실제 데이터가 출력됨을 확인할 수 있다.
조회 수가 많아질수록 추가 쿼리를 계속해서 부르게 되는 문제 발생 : N + 1 문제 라고 함. - 네트워크를 그만큼 왔다갔다 하므로 성능이 좋아질 수가 없다.
▶ JPA에서는 이걸 fetch 조인으로 해결 함.
@Query에 사용된 JPQL 확인
public interface MemberRepository extends JpaRepository<Member, Long> {
// fetch join
@Query("select m from Member m left join fetch m.team")
List<Member> findMemberFetchJoin();
}
테스트 코드 수정
# 호출 repository 메소드 수정
//when
List<Member> members = memberRepository.findMemberFetchJoin();
출력 결과
- 쿼리
- 값 - 프록시가 아니라 실제 데이터가 채워진 것을 볼 수 있다.
연관 관계가 있는 것을 데이터베이스의 join을 활용하여 한번에 다 끌고옴.
▶ 스프링 데이터 JPA - EntityGraph
@EntityGraph(attributePaths = {"team"})
public interface MemberRepository extends JpaRepository<Member, Long> {
//공통 메서드 오버라이드
@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
//JPQL + 엔티티 그래프
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
//메서드 이름으로 쿼리에서 특히 편리하다.
@EntityGraph(attributePaths = {"team"})
List<Member> findByUsername(String username)
}
'프로그래밍 > SpringDataJPA' 카테고리의 다른 글
Auditing (생성일, 수정일, 생성자, 수정자) (0) | 2022.06.19 |
---|---|
JPA Hint & Lock (0) | 2022.06.19 |
벌크성 수정 쿼리 (0) | 2022.06.18 |
스프링 데이터 JPA 페이징과 정렬 (0) | 2022.06.18 |
순수 JPA 페이징과 정렬 (0) | 2022.06.18 |