๊ด€๋ฆฌ ๋ฉ”๋‰ด

DOing

[JPA] Fetch Join ๋ณธ๋ฌธ

JPA

[JPA] Fetch Join

mangdo 2021. 8. 6. 12:43

๐ŸŒฑ Fetch Join

SQL ์กฐ์ธ ์ข…๋ฅ˜๊ฐ€ ์•„๋‹Œ, JPQL์—์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ปฌ๋ ‰์…˜์„ SQL ํ•œ๋ฒˆ์— ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

[LEFT | INNER ] JOIN FETCH

 

[JPQL]

select m from Member m join fetch m.team

 

[SQL]

select m.*, t.*

from member m

inner join team t

on m.team_id = t.id

 

 

๐ŸŒฑ OneToMany + Fetch Join ์‹œ ์ฃผ์˜!

String jpql = "select t from Team t join fetch t.members where t.name = 'ํŒ€A'"
List<Team> teams = em.createQuery(jpql, Team.class).getResultList();

for(Team team : teams) {
    System.out.println("teamname = " + team.getName() + ", team = " + team);
    for (Member member : team.getMembers()) {
    	System.out.println(“-> username = " + member.getUsername()+ ", member = " + member);
    }
}

OneToMany + fetch join์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ปฅํŠ€๊ธฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค!

 

teamname = ํŒ€A, team = Team@0x100
- username = ํšŒ์›1, member = Member@0x200
- username = ํšŒ์›2, member = Member@0x300
teamname = ํŒ€A, team = Team@0x100
- username = ํšŒ์›1, member = Member@0x200
- username = ํšŒ์›2, member = Member@0x300

 

๐ŸŒฑ ์™œ ์ด๋Ÿฐ ๋ปฅํŠ€๊ธฐ ํ˜„์ƒ์ด ๋‚˜์˜ฌ๊นŒ?

ํŒ€A์— ๋Œ€ํ•ด ์—ฐ๊ด€๋œ member๊ฐ€ ๋‘๋ช…์ด๋ผ๊ณ  ํ•˜์ž. join์„ ํ†ตํ•ด ๋‚˜์˜จ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ”์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  ์ด ๊ฒฐ๊ณผ๊ฐ€ JPA๋กœ ๋„˜์–ด์˜ค๊ฒŒ ๋˜๋ฉด, ์ผ๋‹จ JPA๋Š” ๊ฒฐ๊ณผ row ์ˆ˜๋งŒํผ ๋Œ๋ ค์•ผํ•œ๋‹ค. PK๊ฐ’์ด ๋˜‘๊ฐ™๋”๋ผ๋„ ์ผ๋‹จ row ๊ฐฏ์ˆ˜๋งŒํผ ๋งŒํผ ๋งŒ๋“ค์–ด์•ผํ•œ๋‹ค. ์ค‘๋ณต์„ ์ œ๊ฑฐํ• ์ง€ ๋ง์ง€๋Š” ์ถ”ํ›„์— ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•˜๊ฒŒ๋” ํ•œ๋‹ค. JPA ์ž…์žฅ์—์„œ๋Š” ์ผ๋‹จ ๋˜‘๊ฐ™์€ ํŒ€A๊ฐ€ ๋‘๊ฐœ๋‹ค. ์ด ํŒ€A๋Š” ํšŒ์›1, ํšŒ์›2๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทธ๋ฆผ์ด ๊ทธ๋ ค์ง„๋‹ค.

 

๐ŸŒฑ ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋Š”๊ฐ€?

 ๊ฐ™์€ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง€๋Š” ์™„๋ฒฝํžˆ ๋™์ผํ•œ TeamA๊ฐ€ ๋‘๋ฒˆ ๋งŒ๋“ค์–ด์ง€๋Š” ๊ฒƒ์ด ๋ฌธ์ œ์˜€๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์ค‘๋ณต๋œ TeamA๋ฅผ ์‚ญ์ œํ•˜๋ฉด ๋œ๋‹ค. 

์ด๋ฅผ ์œ„ํ•ด JPQL์˜ DISTINCT๋Š” ๋‘๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

1. SQL์— DISTINCT๋ฅผ ์ถ”๊ฐ€
2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์—”ํ‹ฐํ‹ฐ ์ค‘๋ณต ์ œ๊ฑฐ

     -> ์ด๋•Œ ๊ฐ™์€ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง„ Team ์—”ํ‹ฐํ‹ฐ ์ œ๊ฑฐ

String jpql = "select distinct t from Team t join fetch t.members where t.name = 'ํŒ€A'"
List<Team> teams = em.createQuery(jpql, Team.class).getResultList();

for(Team team : teams) {
    System.out.println("teamname = " + team.getName() + ", team = " + team);
    for (Member member : team.getMembers()) {
    	System.out.println(“-> username = " + member.getUsername()+ ", member = " + member);
    }
}

 

 

๐ŸŒฑ Fetch Join ํ•œ๊ณ„

1. Fetch Join ๋Œ€์ƒ์—๋Š” ๋ณ„์นญ์„ ์ฃผ๋ฉด ์•ˆ๋œ๋‹ค.

String jpql = "select distinct t from Team t join fetch t.members as m" // ์•ˆ๋จ
String jpql = "select distinct t from Team t join fetch t.members as m where m.age > 10" // ์•ˆ๋จ

 fetch join์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‚˜๋ž‘ ์—ฐ๊ด€๋œ ๊ฒƒ๋“ค์€ ์ „๋ถ€ ๋“ค๊ณ  ์˜ค๋Š” ์ผ์ด๋‹ค. ๋งŒ์•ฝ ๋‚˜์™€ ์—ฐ๊ด€๋œ ์• ๋“ค์„ ๊ฑธ๋Ÿฌ์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ๋‹ค๋ฉด fetch join์„ ์“ฐ๋ฉด ์•ˆ๋œ๋‹ค. ๊ทธ๋Ÿฐ๊ฑธ ์›ํ•œ๋‹ค๋ฉด team.getMember()๋กœ ๊ฐ€์ ธ์˜ค๋ฉด ์•ˆ๋˜๊ณ  member์—์„œ ๋”ฐ๋กœ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ๋งž๋‹ค. ๋ฐ์ดํ„ฐ์˜ ์ •ํ•ฉ์„ฑ, JPA์˜ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ์‚ฌ์ƒ์— ๋งž์ง€ ์•Š๋Š” ํ–‰์œ„์ด๋‹ค.

 ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ž…์žฅ์—์„œ ์ƒ๊ฐํ•ด๋ณด์ž. ๋˜‘๊ฐ™์€ teamA์ธ๋ฐ ์–ด๋–ค ์• ๋Š” member 100๊ฐœ ์ค‘์— 100๊ฐœ๋ฅผ ๋‹ค๊ฐ€์ ธ์˜ค๊ณ  ๋‹ค๋ฅธ ์• ๋Š” member 100๊ฐœ ์ค‘ 5๊ฐœ๋ฅผ ๊ฐ€์ง€๊ณ  ์™”๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ž…์žฅ์—์„œ๋Š” ๊ต‰์žฅํžˆ ๋‚œ๊ฐํ•œ ์ƒํ™ฉ์ผ ๊ฒƒ์ด๋‹ค. ๋ณ„์นญ์€ join fetch๋ฅผ ์—ฌ๋Ÿฌ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณ๊ฐ€๋Š” ๋“ฑ์˜ ๋ณต์žกํ•œ ํ–‰์œ„์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ๊ฐ€๊ธ‰์  ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

2. ๋‘˜ ์ด์ƒ์˜ ์ปฌ๋ ‰์…˜์„ ํŒจ์น˜์กฐ์ธํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

: ๋ฐ์ดํ„ฐ๊ฐ€ ๋ช‡๋ฐฐ๋กœ ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์–ด ์œ„ํ—˜ํ•˜๋‹ค. ํŒจ์น˜์กฐ์ธ์˜ ์ปฌ๋ ‰์…˜์€ ํ•˜๋‚˜๋งŒ ์ง€์ •ํ•˜๋„๋ก ํ•˜์ž.

 

3. ์ปฌ๋ ‰์…˜์„ ํŒจ์น˜์กฐ์ธํ•˜๋ฉด ํŽ˜์ด์ง• API()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

- OneToOne, ManyToOne์€ ํŽ˜์น˜์กฐ์ธํ•ด๋„ ํŽ˜์ด์ง•์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

- ํ•˜์ง€๋งŒ OneToMany๋Š” ๋ฐ์ดํ„ฐ ๋ปฅํŠ€๊ธฐ๊ฐ€ ๋˜๊ธฐ๋•Œ๋ฌธ์— fetch join์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

   : DB ์กฐํšŒ ๊ฒฐ๊ณผ ๊ฐ’์ด ์•„๋ž˜์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์œผ๋ฉด์„œ ํŽ˜์ด์ง•์ด 1์ด๋ผ๋ฉด ํŒ€A๋Š” ํšŒ์›1๋ฐ–์— ๊ฐ–์ง€ ๋ชปํ•œ๋‹ค. ์‹ค์ œ๋กœ๋Š” ํŒ€A๊ฐ€ ํšŒ์›1, ํšŒ์›2๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ ! ์ด๋Ÿฐ ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ๋ฒ„์ „๋งˆ๋‹ค ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋•Œ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋Š” ๊ฒฝ๊ณ  ๋กœ๊ทธ๋ฅผ ๋‚ ๋ฆฌ๊ณ  ํŽ˜์ด์ง•์ฟผ๋ฆฌ๊ฐ€ ์•„๋‹Œ ์ „์ฒด ๋ฐ์ดํ„ฐ ์กฐํšŒ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๊ณ  ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.(๋งค์šฐ ์œ„ํ—˜!)

 

๐ŸŒฑ ํŒจ์น˜์กฐ์ธ ์ •๋ฆฌ

  • ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ปฌ๋ ‰์…˜์„ SQL ํ•œ๋ฒˆ์— ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.
  • ์—”ํ‹ฐํ‹ฐ์— ์ง์ ‘ ์ ์šฉํ•˜๋Š” ๊ธ€๋กœ๋ฒŒ ๋กœ๋”ฉ ์ „๋žต๋ณด๋‹ค ์šฐ์„ ๋œ๋‹ค.
    •  FetchType.LAZY์ธ์ง€ EAGER์ธ์ง€ ์ƒ๊ด€์—†์ด ๋ฌด์กฐ๊ฑด fetch join์ด ๋จนํžŒ๋‹ค.
  • ์‹ค๋ฌด์—์„œ๋Š” ๊ธ€๋กœ๋ฒŒ ๋กœ๋”ฉ ์ „๋žต์€ ๋ชจ๋‘ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ํ•˜๊ณ  ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์— fetch join์„ ์ด์šฉํ•œ๋‹ค.
  • Fetch join์ด ๋ชจ๋“  ๊ฒƒ์„ ํ•ด๊ฒฐํ•ด์ฃผ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋ฅผ ์œ ์ง€ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ํšจ๊ณผ์ ์ด๋‹ค!
    • ๋งŒ์•ฝ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ์กฐํšŒํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์›๋ž˜ ๊ฐ€์ง„ ๋ชจ์–‘์ด ์•„๋‹Œ ์ „ํ˜€ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์•ผํ•œ๋‹ค๋ฉด, ํŒจ์น˜์กฐ์ธ์ด ์•„๋‹Œ ์ผ๋ฐ˜์กฐ์ธ+DTO๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ํšจ๊ณผ์ ์ด๋‹ค!