인프런 커뮤니티 질문&답변

gusdn85554님의 프로필 이미지

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

select 쿼리 발생

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

gusdn85554님의 프로필 이미지
gusdn85554
질문자

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문제가 발생한다
이 말씀을 잘 모르겠습니다

감사합니다.

김영한님의 프로필 이미지
김영한
지식공유자

2022. 02. 12. 12:01

안녕하세요. gusdn85554님

제가 설명을 잘못드렸네요. member가 아니라 team을 복수로 조회하시면 됩니다.

Team team = em.find(Team.class, team1.getId()); 이렇게 조회하는 대신에

JPQL을 사용해서 team을 리스트로 조회해서 테스트해보시면 이해가 되실거에요.

감사합니다.

 

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

gusdn85554님의 프로필 이미지
gusdn85554
질문자

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. 전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 실행 방법을 알려주세요.

2. 어떻게 문제를 확인할 수 있는지 자세한 설명을 남겨주세요.

감사합니다.