티스토리 뷰

Java

JPA, OneToMany, FetchType, fetch join+distinct

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

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

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

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,1,m1
2,1,m2
3,1,m3
4,2,m4
5,2,m5
6,2,m6
7,3,m7
8,3,m8
9,4,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 = "manyToOne_member")
public class Member {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;
    private String name;

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

    private String name;

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

1.3 표출하기

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

public static void print(Team team) {
    String teamName = team.getName();
    List<String> memberNames = team.getMembers()
            .stream()
            .map(Member::getName)
            .collect(Collectors.toList());

    System.out.printf(">>> %s : ", teamName);
    memberNames.forEach((memberName) -> System.out.printf("%s,", memberName));
    System.out.println();
}

2. EntityManager.find

2.1 실행코드

public static void logic(EntityManager em) {
    Team team = em.find(Team.class, 1L);
    print(team);
}

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

Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_, members1_.team_id as team_id3_0_1_, members1_.member_id as member_i1_0_1_, members1_.member_id as member_i1_0_2_, members1_.name as name2_0_2_, members1_.team_id as team_id3_0_2_ from manyToOne_team team0_ left outer join manyToOne_member members1_ on team0_.team_id=members1_.team_id where team0_.team_id=?
>>> team1 : m1,m2,m3,

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

Hibernate: select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from manyToOne_team team0_ where team0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team1 : m1,m2,m3,

3. JPQL

3.1 Single

3.1.1 실행코드

String jpql = "select t from Team t where t.id=:id";
Team team = em.createQuery(jpql, Team.class)
        .setParameter("id", 1L)
        .getSingleResult();
print(team);

3.1.2 FetchType.EAGER 실행결과(query 2회)

Hibernate: select team0_.team_id as team_id1_1_, team0_.name as name2_1_ from manyToOne_team team0_ where team0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team1 : m1,m2,m3,

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

Hibernate: select team0_.team_id as team_id1_1_, team0_.name as name2_1_ from manyToOne_team team0_ where team0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team1 : m1,m2,m3,

3.2 Multiple

3.2.1 실행코드

String jpql = "select t from Team t";
List<Team> teams = em.createQuery(jpql, Team.class)
        .getResultList();
for (Team team : teams) {
    print(team);
}

3.2.2 FetchType.EAGER 실행결과(query 6회)

Hibernate: select team0_.team_id as team_id1_1_, team0_.name as name2_1_ from manyToOne_team team0_
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team1 : m1,m2,m3,
>>> team2 : m4,m5,m6,
>>> team3 : m7,m8,
>>> team4 : m9,
>>> team5 : m10,

3.2.3 FetchType.LAZY 실행결과(query 6회)

Hibernate: select team0_.team_id as team_id1_1_, team0_.name as name2_1_ from manyToOne_team team0_
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team1 : m1,m2,m3,
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team2 : m4,m5,m6,
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team3 : m7,m8,
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team4 : m9,
Hibernate: select members0_.team_id as team_id3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.name as name2_0_1_, members0_.team_id as team_id3_0_1_ from manyToOne_member members0_ where members0_.team_id=?
>>> team5 : m10,

4. JPQL(distinct, fetch join)

4.1 Single(FetchType.LAZY)

4.1.1 실행코드

String jpql = "select distinct t from Team t join fetch t.members where t.id=:id";
List<Team> teams = em.createQuery(jpql, Team.class)
        .setParameter("id", 1L)
        .getResultList();
for (Team team : teams) {
    print(team);
}

4.1.2 실행결과(query 1회)

Hibernate: select distinct team0_.team_id as team_id1_1_0_, members1_.member_id as member_i1_0_1_, team0_.name as name2_1_0_, members1_.name as name2_0_1_, members1_.team_id as team_id3_0_1_, members1_.team_id as team_id3_0_0__, members1_.member_id as member_i1_0_0__ from manyToOne_team team0_ inner join manyToOne_member members1_ on team0_.team_id=members1_.team_id where team0_.team_id=?
>>> team1 : m1,m2,m3,

4.2 Multiple(FetchType.LAZY)

4.2.1 실행코드

String jpql = "select distinct t from Team t join fetch t.members";
List<Team> teams = em.createQuery(jpql, Team.class)
        .getResultList();
for (Team team : teams) {
    print(team);
}

4.2.2 실행결과(query 1회)

Hibernate: select distinct team0_.team_id as team_id1_1_0_, members1_.member_id as member_i1_0_1_, team0_.name as name2_1_0_, members1_.name as name2_0_1_, members1_.team_id as team_id3_0_1_, members1_.team_id as team_id3_0_0__, members1_.member_id as member_i1_0_0__ from manyToOne_team team0_ inner join manyToOne_member members1_ on team0_.team_id=members1_.team_id
>>> team1 : m1,m2,m3,
>>> team2 : m4,m5,m6,
>>> team3 : m7,m8,
>>> team4 : m9,
>>> team5 : m10,

 

 

 

 

'Java' 카테고리의 다른 글

JAVA, Optional  (0) 2021.12.10
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함