JPA의 @ManyToOne 과 @OneToMany 에 대해 알아보자.
- 테이블 :
Member,Team member목록을 조회할 때1
2
3
4
5
6
7
8
9
10
11
12@Controller public MemberController { @Autowired private MemberRepository memberRepository; @GetMapping("/members") @ResponseBody public List<Member> getMembers() { return memberRepository.findAll(); } }
@ManyToOne
- Member-Team
1
2
3
4
5
6
7@Entity @Table(name="member") class Member { ... @ManyToOne private Team team; } member를 조회하면 다음과 같은 결과가 나온다.1
2
3team 조회 where id=team1 team 조회 where id=team2 ...- 결과를 통해 알 수 있는 사실은
member의 개수만큼 조회되는 것이 아니라 (member조회 +team조회) 되고 있다. - 즉,
n+1만큼 더해서 조회되고 있다. 해당 이유를 살펴보면 다음과 같다.
JpaRepository에서 제공하는method들은 기본적으로 전부@Transactional이다.- 따라서
findAll()을 하면member를 가져온 다음에member가 참조하고 있는team을 가져온다.
** 만약, 아래 테스트 코드를 돌리게 되면 testSelect() 메서드 내 같은 트랜잭션 안에서 member 들이 참조하고 있는 객체가 이미 save를 하면서 1차 캐시에 캐싱되어 있기 때문에 findAll()을 할 때 다시 불러올 필요가 없으므로 1번만 조회한다.
1 | |
N+1 문제 해결 방법
Fetch Join 사용
1 | |
조회 결과를 살펴보면
member inner join team on member.team_id=team.idinner join이 되고 있다.- 따라서,
team있는member만 조회된다.
@EntityGraph 사용
1 | |
1 | |
조회 결과를 살펴보면
member left outer join team on member.team_id=team.idleft outer join이 되고 있다.- 따라서,
team없는memeber도 조회된다.
@OneToMany
- Team-Member
1 | |
- MappedBy = “team”
- 관계의 주인을
Member클래스의team으로 넘겨준다. - 관계의 주인 쪽에 관계가 설정되어야만 데이터베이스에 반영된다.
- 만약,
members에member를 추가하려면 아래와 같이 관계의 주인쪽에 관계를 설정해준다.
- 관계의 주인을
1 | |