ABAP DUMP ERROR 24시

Jpql fetch join 이 뭐야? ,N+1 예시 본문

[WEB]Back-end/JPA

Jpql fetch join 이 뭐야? ,N+1 예시

이운형 2022. 1. 22. 06:51
반응형

# 인프런 김영한의 자바 ORM 표준 JPA 프로그래밍 - 기본편을 개인적으로 정리한 글입니다.

 

정리


Q . fetch join이 뭐야?

실무에서 자주 사용하며, 연관된 엔티티 컬렉션을 sql문 한방으로 조회하는 쿼리다.

흔히 N+1 문제의 해결 방안으로 제시되곤 한다.

 

//N+1 문제란 JPA에서 query 1개를 호출했는데 DB에는 N개의 query가 호출되어 나가는 현상.

 

Q .fetch = fetchType.EAGER 와 fetch join과의 차이점이 뭐야?

둘다 join query가 나가는 것은 비슷하다.

하지만 EARGER묵시적인 특성으로.  내가 나타내지 않는 쿼리명령어 이외의  쿼리가 나가면서 join 이 이루어진다.

따라서 추적이 어렵다.

fetch join은 암시적인 특성으로, 내가 join 하고싶은 객체들을 찝어서 쿼리명령어를 작성하기 때문에 추적이 쉽다.

 

 

Q. fetch join 어떻게 사용해?

"select m from Member m join fetch m.team";

가져와 (맴버를) 어디서 (맴버로 부터) 함께 가져와 (맴버의 팀도 같이)

예시와 같이 from 뒤에 사용되며 member와 연관된 team을 가져오고 싶을때 다음과 같이 사용한다.

 

즉 함께 Join된 새부 내용을 가져오고싶을때 사용한다.

 

살펴보기


1.Member가 team의 fk 를 갖는, 즉 왜래키를 갖는 엔티티가 주인이 된다 라는 전략으로 class를 작성하였다. + 양방향 연관관계

2. 원하는 결과는 다음과 같다.

<왼쪽 3개는 Member Table 나머지 두개는 team Table    + inner join 전략>

id name team_id id name
1 회원A 1 1 팀A
2 회원B 1 2 팀B
3 회원C 2 3 팀C

 

@Entity
@Getter@Setter
public class Team {

    @Id@GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team" )
    private List<Member> members = new ArrayList<>();



}
@Entity
@Getter
@Setter
public class Member{

    @Id@GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;


    @Column(name = "NAME")
    private String username;

    private int age;
    
    @Override
    public String toString() {
        return "Member{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }

    public void changeTeam(Team team){
        this.team = team;
        team.getMembers().add(this);
    }
}

 

 

2. Test에 Member , team 변수들을 생성해준다.

Team teamA = new Team();
teamA.setName("팀A");
em.persist(teamA);

Team teamB = new Team();
teamB.setName("팀B");
em.persist(teamB);

Team teamC = new Team();
teamC.setName("팀C");
em.persist(teamC);

Member member1 = new Member();
member1.setUsername("회원1");
member1.changeTeam(teamA);
em.persist(member1);


Member member2 = new Member();
member2.setUsername("회원2");
member2.changeTeam(teamB);
em.persist(member2);

Member member3 = new Member();
member3.setUsername("회원3");
member3.changeTeam(teamC);
em.persist(member3);

Case1 ) fetch join 사용 안했을 시 = > N+1문제 발생

    String query = "select m from Member m";

    List<Member> members = em.createQuery(query, Member.class)
            .getResultList();

    for (Member member : members) {
        System.out.println("members = " + member.getUsername()+
                "teamName =" + member.getTeam().getName());
    }

//회원1 ,팀A(SQL);// 회원 2, 팀A(1차캐시)

1번째 : member를 조회하는 query

2번째 : 회원 1에 맞는 TeamA를 가져오는 query

3번째 : 회원 2에 맞는 TeamA를 가져온다 ==> 이미 TeamA를 가져왔기때문에 1차 캐시에서 가져오므로 query안나감

4번째 : 회원 3에 맞는 TeamB를 가져오는 query

=> 총 3방의 쿼리가 나간다.

 

 

Case2 ) fetch join 사용 했을시

String query = "select m from Member m join fetch m.team";

List<Member> members = em.createQuery(query, Member.class)
        .getResultList();

for (Member member : members) {
    System.out.println("members = " + member.getUsername()+
            "teamName =" + member.getTeam().getName());
}

member 조회할때 Team 정보까지 가져온다.

=> 총 1방의 쿼리가 나간다.

반응형
Comments