22.02.03 01:04 작성
·
223
0
영한님 서포터즈님들 안녕하세요
프로젝트를 하다가 갑자기 궁금한 점이 생겨 테스트를 만들어보고
제가 현재 어느 부분에서 헤매고 있는지 몰라서 질문드립니다,,
```java
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
public void addTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
Main 부분
Team team1 = new Team();
team1.setName("team1");
em.persist(team1);
Member member1 = new Member();
member1.setName("member1");
Member member2 = new Member();
member2.setName("member2");
Member member3 = new Member();
member3.setName("member3");
member1.addTeam(team1);
member2.addTeam(team1);
member3.addTeam(team1);
em.persist(member1);
em.persist(member2);
em.persist(member3);
em.flush();
em.clear();
Team team = em.find(Team.class, team1.getId());
for (Member member : team.getMembers()) {
//select 쿼리가 member의 개수만큼 나가야한다고 생각
System.out.println("member.getName() = " + member.getName());
}
```
db에도 잘 저장되있습니다.
제가 궁금한 점은 주석과 같이 member.getName을 사용하게 되면 member 수만큼 쿼리가 나가야한다고 생각이 드는데 제가 어느 개념을 놓치고 있는지 너무 궁금합니다..
프록시 부분을 다시 봐도 member의 실제 값을 사용하는데 어떻게 List<Member> members를 한 번에 조회해오지? 라는 생각이 듭니다,,
혹시 어느 부분을 놓쳤는지 말씀해주시면 바로 공부해보도록 하겠습니다
감사합니다
추가로
```java
Team team = em.getReference(Team.class, team1.getId());
```
제가 프록시와 헷갈려서 위와 같이 코드를 작성하고 다시 해봤는데도 똑같습니다,,
답변 4
0
2022. 02. 07. 14:28
안녕하세요 영한님 답변 감사합니다.
다만 N+1 문제가 발생하려면 처음에 조회하는 member 자체가 지금처럼 하나가 아니라 둘 이상이어야 합니다.라는게 무슨 말씀이신지 이해가 되질 않습니다
members에 있는 member들은 한번에 실제 객체를 조회하여서 N+1이 발생하지 않는 것이다라고 이해를 했습니다.
JPA2에서 가르쳐주신 Order과 Member와의 관계를 연관지어서 생각해봤는데, Order를 1번 조회하면 Member가 N번만큼 조회되어 N+1이 발생된다. 이 때는 N -> 1로 조회했기 때문에 N+1이 발생한 이유는 이해됐습니다.
Team -> Member는 1 -> N으로 조회되는데 member 자체가 둘 이상이 되어야 N+1문제가 발생한다
이 말씀을 잘 모르겠습니다
감사합니다.
0
2022. 02. 06. 18:05
안녕하세요. gusdn85554님
이 경우에는 1번만 조회되는 것이 맞습니다.
team.getMembers()를 채우기 위해 지연로딩으로 실행되는 쿼리를 보시면 이해가 되실거에요.
select
members0_.TEAM_ID as team_id10_6_0_,
members0_.MEMBER_ID as member_i1_6_0_,
members0_.MEMBER_ID as member_i1_6_1_,
members0_.createdBy as createdb2_6_1_,
members0_.createdDate as createdd3_6_1_,
members0_.lastModifiedDate as lastmodi4_6_1_,
members0_.lastmodifiedBy as lastmodi5_6_1_,
members0_.city as city6_6_1_,
members0_.name as name7_6_1_,
members0_.street as street8_6_1_,
members0_.TEAM_ID as team_id10_6_1_,
members0_.zipcode as zipcode9_6_1_
from
Member members0_
where
members0_.TEAM_ID=?
이미 해당 팀에 소속된 모든 회원 정보를 한번에 조회하게 됩니다. 여기서 핵심은 team -> members의 관계는 프록시 이지만, members 자체는 쿼리 한번에 조회할 수 있다는 점입니다.
N+1 문제가 발생하려면 처음에 조회하는 member 자체가 지금처럼 하나가 아니라 둘 이상이어야 합니다.
감사합니다.
0
2022. 02. 05. 14:09
안녕하세요 영한님
제가 sql 을 안올렸었네요,, 죄송합니다
select
team0_.TEAM_ID as TEAM_ID1_10_0_,
team0_.name as name2_10_0_
from
Team team0_
where
team0_.TEAM_ID=?
team.getClass() = class jpabook.domain.Team
Hibernate:
select
members0_.TEAM_ID as TEAM_ID10_6_0_,
members0_.MEMBER_ID as MEMBER_I1_6_0_,
members0_.MEMBER_ID as MEMBER_I1_6_1_,
members0_.createdBy as createdB2_6_1_,
members0_.createdDate as createdD3_6_1_,
members0_.lastModifiedDate as lastModi4_6_1_,
members0_.lastmodifiedBy as lastmodi5_6_1_,
members0_.city as city6_6_1_,
members0_.name as name7_6_1_,
members0_.street as street8_6_1_,
members0_.TEAM_ID as TEAM_ID10_6_1_,
members0_.zipcode as zipcode9_6_1_
from
Member members0_
where
members0_.TEAM_ID=?
member = jpabook.domain.Member@656922a0
member.getName() = member1
member = jpabook.domain.Member@656922a0
member = jpabook.domain.Member@5922d3e9
member.getName() = member2
member = jpabook.domain.Member@5922d3e9
member = jpabook.domain.Member@7d57dbb5
member.getName() = member3
member = jpabook.domain.Member@7d57dbb5
sql 쿼리 입니다,
https://drive.google.com/file/d/1TE6P3omeTuFu6VyJdcQ_p9nttD5cz5AS/view?usp=sharing
0
2022. 02. 05. 13:45
안녕하세요. gusdn85554님
1. 실행 결과 로그를 자세히 남겨주세요. 특히 실행되는 모든 sql을 남겨주세요.
2. 전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.
구글 드라이브 업로드 방법은 다음을 참고해주세요.
주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요
추가로 다음 내용도 코멘트 부탁드립니다.
1. 실행 방법을 알려주세요.
2. 어떻게 문제를 확인할 수 있는지 자세한 설명을 남겨주세요.
감사합니다.
2022. 02. 12. 12:01
안녕하세요. gusdn85554님
제가 설명을 잘못드렸네요. member가 아니라 team을 복수로 조회하시면 됩니다.
Team team = em.find(Team.class, team1.getId()); 이렇게 조회하는 대신에
JPQL을 사용해서 team을 리스트로 조회해서 테스트해보시면 이해가 되실거에요.
감사합니다.