티스토리 뷰

Java/JPA

JPA, ManyToOne, FetchType, fetch join

hwangyoungjae 2021. 12. 2. 16:55
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

- Entity의 ManyToOne의 FetchType에 대해 어떤식으로 처리되는지 정리

- JPQL을 사용했을때 발생하는 N + 1 문제를 fetch join으로 해결

 

1. 준비

1.1 DDL & Records

create table `member`
(
    member_id bigint auto_increment primary key,
    team_id   bigint       null,
    name      varchar(255) null
);
create table `team`
(
    team_id bigint auto_increment primary key,
    name    varchar(255) null
);
# member
member_id,team_id,name
1,<null>,m1
2,1,m2
3,2,m3
4,2,m4
5,3,m5
6,3,m6
7,4,m7
8,4,m8
9,5,m9
10,5,m10
# team
team_id,name
1,team1
2,team2
3,team3
4,team4
5,team5

1.2 Entity

@Getter @Setter
@Entity @Table(name = "member")
public class Member {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;
    private String name;

    @ManyToOne(fetch = ?, cascade = CascadeType.ALL)
    @JoinColumn(name = "team_id")
    private Team team;
}
@Getter @Setter
@Entity @Table(name = "team")
public class Team {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "team_id")
    private Long id;
    private String name;
}

1.3 표출하기

Member 객체와 Team을 보기좋게 표출하기 위한 print method

public static void print(Member member) {
  String memberName = member.getName();
  String teamName = null;
  if (member.getTeam() != null) {
    teamName = member.getTeam().getName();
  }
  System.out.printf(">>> %s-%s%n", memberName, teamName);
}

2. EntityManager.find

2.1 실행코드

public static void logic(EntityManager em) {
  Member member = em.find(Member.class, 2L);
  print(member);

2.2 FetchType.EAGER 실행결과(query 1회)

Hibernate: select member0_.member_id as member_i1_0_0_, member0_.name as name2_0_0_, member0_.team_id as team_id3_0_0_, team1_.team_id as team_id1_1_1_, team1_.name as name2_1_1_ from member member0_ left outer join team team1_ on member0_.team_id=team1_.team_id where member0_.member_id=?
>>> m2-team1

2.3 FetchType.LAZY 실행결과(query 2회)

Hibernate: select member0_.member_id as member_i1_0_0_, member0_.name as name2_0_0_, member0_.team_id as team_id3_0_0_ from member member0_ where member0_.member_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
>>> m2-team1

3. JPQL

3.1 Single

3.1.1 실행코드

String jpql = "select m from Member m join fetch m.team where m.id=:id";
Member member = em.createQuery(jpql, Member.class)
  .setParameter("id", 2L).getSingleResult();
print(member);

3.1.2 FetchType.EAGER(query 2회)

Hibernate: select member0_.member_id as member_i1_0_, member0_.name as name2_0_, member0_.team_id as team_id3_0_ from member member0_ where member0_.member_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
>>> m2-team1

3.1.3 FetchType.LAZY(query 2회)

Hibernate: select member0_.member_id as member_i1_0_, member0_.name as name2_0_, member0_.team_id as team_id3_0_ from member member0_ where member0_.member_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
>>> m2-team1

3.2 Multiple

3.2.1 실행코드

String jpql = "select m from Member m";
List<Member> resultList = em.createQuery(jpql, Member.class)
  .getResultList();
for (Member member : resultList) {
  print(member);
}

3.2.2 FetchType.EAGER(query 6회)

Hibernate: select member0_.member_id as member_i1_0_, member0_.name as name2_0_, member0_.team_id as team_id3_0_ from member member0_
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=?
>>> m1-null
>>> m2-team1
>>> m3-team2
>>> m4-team2
>>> m5-team3
>>> m6-team3
>>> m7-team4
>>> m8-team4
>>> m9-team5
>>> m10-team5

3.2.3 FetchType.LAZY(query 6회)

Hibernate: select member0_.member_id as member_i1_0_, member0_.name as name2_0_, member0_.team_id as team_id3_0_ from manyToOne_member member0_
>>> m1-null
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from manyToOne_team team0_ where team0_.team_id=?
>>> m2-team1
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from manyToOne_team team0_ where team0_.team_id=?
>>> m3-team2
>>> m4-team2
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from manyToOne_team team0_ where team0_.team_id=?
>>> m5-team3
>>> m6-team3
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from manyToOne_team team0_ where team0_.team_id=?
>>> m7-team4
>>> m8-team4
Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from manyToOne_team team0_ where team0_.team_id=?
>>> m9-team5
>>> m10-team5

 

4. JPQL(fetch join)

fetch join을 통한 N + 1 해결

4.1 Single(FetchType.LAZY)

4.1.1 실행코드

String jpql = "select m from Member m left join fetch m.team where m.id=:id";
Member member = em.createQuery(jpql, Member.class)
  .setParameter("id", 2L).getSingleResult();
print(member);

4.1.2 실행결과(query 1회)

Hibernate: select member0_.member_id as member_i1_0_0_, team1_.team_id as team_id1_1_1_, member0_.name as name2_0_0_, member0_.team_id as team_id3_0_0_, team1_.name as name2_1_1_ from member member0_ inner join team team1_ on member0_.team_id=team1_.team_id where member0_.member_id=?
>>> m2-team1

4.2 Multiple(FetchType.LAZY)

4.2.1 실행코드

String jpql = "select m from Member m left join fetch m.team";
List<Member> resultList = em.createQuery(jpql, Member.class)
  .getResultList();
for (Member member : resultList) {
  print(member);
}

4.2.2 실행결과(query 1회)

Hibernate: select member0_.member_id as member_i1_0_0_, team1_.team_id as team_id1_1_1_, member0_.name as name2_0_0_, member0_.team_id as team_id3_0_0_, team1_.name as name2_1_1_ from manyToOne_member member0_ left outer join manyToOne_team team1_ on member0_.team_id=team1_.team_id
>>> m2-team1
>>> m3-team2
>>> m4-team2
>>> m5-team3
>>> m6-team3
>>> m7-team4
>>> m8-team4
>>> m9-team5
>>> m10-team5
>>> m1-null

'Java > JPA' 카테고리의 다른 글

JPA, Composite Key, IdClass  (0) 2021.12.03
JPA, DynamicUpdate, DynamicInsert  (0) 2021.10.28
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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 31
글 보관함