Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Thymeleaf
- 스프링
- kotlin
- QueryDSL
- AOP
- SpringBoot
- Android
- pointcut
- Spring Boot
- 백준
- java
- 알고리즘
- 자바
- JPQL
- db
- 스프링 핵심 원리
- spring
- 스프링 핵심 기능
- 김영한
- JDBC
- Greedy
- Servlet
- transaction
- 인프런
- Exception
- Proxy
- springdatajpa
- 그리디
- jpa
- http
Archives
- Today
- Total
개발자되기 프로젝트
@EntityGraph 본문
1. @EntityGraph?
- 연관된 엔티티들을 SQL 한번에 조회하는방법
2. 사례
- member -> team은 다대일 지연로딩 관계.
- 따라서 team에 대한 데이터 접근(team.get~) 시 쿼리가 날라감.
- 따라서 member에 대한 쿼리 외에 team의 데이터 조회하는 쿼리 나감.
- 즉 N+1 이슈 발생함.
3. member만 조회
@Test
public void findMemberLazy(){
//given
//member1 -> TeamA
//member2 -> TeamB
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
teamRepository.save(teamA);
teamRepository.save(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 10, teamB);
memberRepository.save(member1);
memberRepository.save(member2);
em.flush();
em.clear();
//when
List<Member> members = memberRepository.findAll();
System.out.println("===================");
for (Member member : members) {
System.out.println("member.getUserName() = " + member.getUserName());
}
}
멤버 조회하는 쿼리만 날라감.
select
member0_.member_id as member_i1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.user_name as user_nam3_0_
from
member member0_
===================
member.getUserName() = member1
member.getUserName() = member2
4. member의 팀이름 조회
- member.getTeam().getName()
- 지연로딩 이므로 team.getName()실행 시 프록시 초기화됨.
- 이 때 team을 조회하는 쿼리 날라감.
- N+1!!!
@Test
public void findMemberLazy(){
//given
//member1 -> TeamA
//member2 -> TeamB
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
teamRepository.save(teamA);
teamRepository.save(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 10, teamB);
memberRepository.save(member1);
memberRepository.save(member2);
em.flush();
em.clear();
//when
List<Member> members = memberRepository.findAll();
System.out.println("===================");
for (Member member : members) {
System.out.println("member.getUserName() = " + member.getUserName());
System.out.println("member.getTeam().getName() = " + member.getTeam().getName());
}
}
select
member0_.member_id as member_i1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.user_name as user_nam3_0_
from
member member0_
===================
member.getUserName() = member1
select
team0_.team_id as team_id1_1_0_,
team0_.name as name2_1_0_
from
team team0_
where
team0_.team_id=?
member.getUserName() = member2
select
team0_.team_id as team_id1_1_0_,
team0_.name as name2_1_0_
from
team team0_
where
team0_.team_id=?
5. fetch join 사용
@Query("select m from Member m join fetch m.team t")
List<Member> findMemberFetchJoin();
@Test
public void findMemberLazy(){
//given
//member1 -> TeamA
//member2 -> TeamB
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
teamRepository.save(teamA);
teamRepository.save(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 10, teamB);
memberRepository.save(member1);
memberRepository.save(member2);
em.flush();
em.clear();
//when
List<Member> members = memberRepository.findMemberFetchJoin();
System.out.println("===================");
for (Member member : members) {
System.out.println("member.getUserName() = " + member.getUserName());
System.out.println("member.getTeam().getName() = " + member.getTeam().getName());
System.out.println("member.getTeam().getClass() = " + member.getTeam().getClass());
}
}
- fetch join을 사용하면 member조회시 연관엔티티인 team도 모두 조회하여
- team엔티티 생성해서 Team에 넣어둠. 프록시 객체가 아님.
select
member0_.member_id as member_i1_0_0_,
team1_.team_id as team_id1_1_1_,
member0_.age as age2_0_0_,
member0_.team_id as team_id4_0_0_,
member0_.user_name as user_nam3_0_0_,
team1_.name as name2_1_1_
from
member member0_
inner join
team team1_
on member0_.team_id=team1_.team_id
===================
member.getUserName() = member1
member.getTeam().getName() = teamA
member.getTeam().getClass() = class study.datajpa.entity.Team
member.getUserName() = member2
member.getTeam().getName() = teamB
member.getTeam().getClass() = class study.datajpa.entity.Team
6. 문제점, 방법
- 근데 SpringDataJpa는 매번 @Query를 사용하는게 아닌데:?
- 그럼 fetch join 어떻게 적용하지?
- @EntityGraph -> fetch join 적용 가능. 어떤 엔티티에 적용할지 정해줘야함.
- attributePath = {""} -> You can refer to direct properties of the entity or nested properties via a property.nestedProperty.
- 기본적으로 left outer join임
@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
@Test
public void findMemberLazy(){
//given
//member1 -> TeamA
//member2 -> TeamB
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
teamRepository.save(teamA);
teamRepository.save(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 10, teamB);
memberRepository.save(member1);
memberRepository.save(member2);
em.flush();
em.clear();
//when
List<Member> members = memberRepository.findAll();
System.out.println("===================");
for (Member member : members) {
System.out.println("member.getUserName() = " + member.getUserName());
System.out.println("member.getTeam().getName() = " + member.getTeam().getName());
System.out.println("member.getTeam().getClass() = " + member.getTeam().getClass());
}
}
select
member0_.member_id as member_i1_0_0_,
team1_.team_id as team_id1_1_1_,
member0_.age as age2_0_0_,
member0_.team_id as team_id4_0_0_,
member0_.user_name as user_nam3_0_0_,
team1_.name as name2_1_1_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.team_id
===================
member.getUserName() = member1
member.getTeam().getName() = teamA
member.getTeam().getClass() = class study.datajpa.entity.Team
member.getUserName() = member2
member.getTeam().getName() = teamB
member.getTeam().getClass() = class study.datajpa.entity.Team
- @Query, @EntityGraph같이 사용 가능
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
8. NamedGraph
- Member Class에 @NamedEntityGraph 사용 가능
- @NamedAttributeNode(("엔티티 이름"))
@NamedEntityGraph(name = "Member.all", attributeNodes =
@NamedAttributeNode("team"))
@Entity
public class Member {}
- 사용방법
- @EntityGraph("name")
@EntityGraph("Member.all")
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
8. GitHub : 210829 @EntityGraph
'인프런 > [인프런] Spring Data JPA' 카테고리의 다른 글
사용자 정의 Repository (0) | 2021.08.30 |
---|---|
JPA Hint & Lock (0) | 2021.08.29 |
Query Method, 벌크성 수정 쿼리 (0) | 2021.08.29 |
SpringDataJpa 페이징, 정렬 (0) | 2021.08.29 |
JPA의 페이징과 정렬 (0) | 2021.08.29 |
Comments