JPA์™€ ORM

์†ก์œค์žฌยท2025๋…„ 1์›” 13์ผ

๐Ÿ“ŒORM(Object Realational Mapping)

ORM์€ ๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘์„ ์˜๋ฏธํ•œ๋‹ค. Java์™€ ๊ฐ™์€ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด์—์„œ์˜ ๊ฐ์ฒด์™€ RDB์˜ ํ…Œ์ด๋ธ”์„ ์ž๋™์œผ๋กœ ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
ํด๋ž˜์Šค๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— RDB์˜ ํ…Œ์ด๋ธ”๊ณผ ๋ถˆ์ผ์น˜๊ฐ€ ์กด์žฌํ•  ์ˆ˜๋ฐ–์— ์—†๋‹ค. ORM์ด ์ด๋Ÿฌํ•œ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์—ญํ• ์„ ํ•ด์ค€๋‹ค.
ORM์€ SQL ์ž‘์„ฑ์ด ์•„๋‹Œ Java ์ฝ”๋“œ(๋ฉ”์„œ๋“œ)๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

ORM ๊ธฐ๋Šฅ

1. ๊ฐ์ฒด-๊ด€๊ณ„ ๋งคํ•‘

  • ORM์€ ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๋งคํ•‘์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ฆ‰, ํด๋ž˜์Šค์˜ ํ•„๋“œ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ์„ ๋งคํ•‘ํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

2. SQL ์ƒ์„ฑ ๋ฐ ์‹คํ–‰

  • ORM์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋Œ€์‹ ํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ORM์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋„๋ก SQL์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค.

3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ

  • ORM์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ๊ณผ ๋ฌด๊ฒฐ์„ฑ์„ ์œ ์ง€ํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๋ณต์žกํ•œ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ๋ฅผ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

4. ์„ฑ๋Šฅ ์ตœ์ ํ™”

  • ORM์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ํ†ต์‹ ์„ ์ตœ์ ํ™”ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋”ฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‚˜ ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์„ ์ตœ์ ํ™”ํ•˜์—ฌ ๋น ๋ฅธ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

ORM ์žฅ์ 

1. ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ

  • ORM์„ ์‚ฌ์šฉํ•˜๋ฉด SQL ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์„ ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ํŠน์ง•์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ์„ ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ

  • ORM์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์˜ ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์˜ํ–ฅ์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

3. ํ”Œ๋žซํผ ๋…๋ฆฝ์„ฑ

  • ORM์€ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์ง€์›์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ”Œ๋žซํผ์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ต์ฒดํ•  ๋•Œ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.

4. ๋ณด์•ˆ ๊ฐ•ํ™”

  • ORM์„ ์‚ฌ์šฉํ•˜๋ฉด SQL Injection๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ์ทจ์•ฝ์ ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ORM์ด ์ œ๊ณตํ•˜๋Š” ๋ณด์•ˆ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“ŒJPA(Java Persistence API)

JPA๋ž€ ์ž๋ฐ” ORM ๊ธฐ์ˆ ์— ๋Œ€ํ•œ API ํ‘œ์ค€ ๋ช…์„ธ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
JPA๋Š” ORM์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ชจ์•„๋‘” ๊ฒƒ์ด๋ฉฐ, JPA๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” JPA๋ฅผ ๊ตฌํ˜„ํ•œ Hibernate, EclipseLink, DataNucleus ๊ฐ™์€ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
"์ธํ„ฐํŽ˜์ด์Šค"์ด๊ธฐ ๋•Œ๋ฌธ์— JPA๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” JPA๋ฅผ ๊ตฌํ˜„ํ•œ Hibernate, EclipseLink, DataNucleus์™€ ๊ฐ™์€ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

JPA์˜ ์žฅ์ 

  1. ์ƒ์‚ฐ์„ฑ์ด ๋›ฐ์–ด๋‚˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•˜๋‹ค. ๊ฐ์ฒด ์ค‘์‹ฌ ์„ค๊ณ„์— ๋” ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  2. DBMS์— ๋Œ€ํ•œ ์ข…์†์„ฑ์ด ์ค„์–ด๋“ ๋‹ค.
    โ‡’ DB์ฟผ๋ฆฌ๋ฌธ์„ ์ฝ”๋“œ๋‹จ์—์„œ ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. DBMS์—์„œ DB๋งŒ ์ƒ์„ฑํ•˜๊ณ , ํ…Œ์ด๋ธ” ์ƒ์„ฑ&๊ด€๋ฆฌ๋“ฑ ๋งŽ์€ ๋ถ€๋ถ„๋“ค์„ ์ฝ”๋“œ๋‹จ์—์„œ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

JPA์˜ ๋‹จ์ 

  1. JPA๋ฅผ ํ•™์Šตํ•˜๋ ค๋ฉด ๋งŽ์€ ๋…ธ๋ ฅ์ด ๋“ ๋‹ค.
  2. ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ถˆ๋ฆฌํ•˜๋‹ค.
    โ‡’ ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์—์„œ๋Š” ์ด ์ •๋ณด, ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ๋Š” ์ด ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค. SQL๋ฌธ์—์„œ๋Š” joinํ•จ์ˆ˜๋กœ ์ฟผ๋ฆฌ ํ•œ ์ค„์ด๋ฉด ๋๋‚œ๋‹ค.
  3. ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜๋„ ์žˆ๋‹ค.

๐Ÿ“Œ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

JPA์—์„œ๋Š” ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋˜๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด ์ •๋ณด๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์˜ค๋ž˜ ์ง€์†๋˜๋„๋ก ๋ณด๊ด€ํ•œ๋‹ค.
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” JPA๋ฅผ ์ดํ•ดํ•˜๋Š”๋ฐ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์šฉ์–ด์ด๋‹ค.

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ๋…ผ๋ฆฌ์ ์ธ ๊ฐœ๋…
  • ๋ˆˆ์— ๋ณด์ด์ง€ ์•Š์Œ
  • ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ํ†ตํ•ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ ‘๊ทผ

์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ

  • ๋น„์˜์†(new/transient) : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ์ „ํ˜€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ
  • ์˜์†(managed) : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ
  • ์ค€์˜์†(detached) : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์—ˆ๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ
  • ์‚ญ์ œ(remove) : ์‚ญ์ œ๋œ ์ƒํƒœ

EntityManager์˜ ์ฃผ์š” ์—ญํ• 

  • persist(): ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ
  • find(): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ
  • remove(): ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์ œ๊ฑฐ
  • merge(): ์ค€์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ค์‹œ ์˜์† ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ
  • detach(): ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ค€์˜์† ์ƒํƒœ๋กœ ์ „ํ™˜

JPA์˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ๊ฐ์ง€

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๋ฉด, JPA๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ณ€๊ฒฝ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•„ SQL์„ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
Member member = em.find(Member.class, 1L); // ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์กฐํšŒ
member.setName("Alice"); // ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ ๋ณ€๊ฒฝ

em.getTransaction().commit(); // ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ํ†ตํ•ด UPDATE SQL ์‹คํ–‰

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” JPA์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์— ๊ธฐ์—ฌ

  • 1์ฐจ ์บ์‹œ: ๋™์ผ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์บ์‹ฑํ•ด, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ ๋น„์šฉ์„ ์ค„์ž„.
  • ์“ฐ๊ธฐ ์ง€์—ฐ: ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— ํ•œ ๋ฒˆ์— SQL ์‹คํ–‰.
  • ์ง€์—ฐ ๋กœ๋”ฉ (Lazy Loading): ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์‹œ์ ์—๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ.

๐Ÿ“ŒN+1 ๋ฌธ์ œ๋ž€?

์—ฐ๊ด€ ๊ด€๊ณ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด์Šˆ๋กœ ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๊ฒฝ์šฐ์— ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜(n) ๋งŒํผ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์กฐํšŒ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๊ฒŒ ๋œ๋‹ค. ์ฆ‰, 1๋ฒˆ์˜ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ธ์„ ๋•Œ ์˜๋„ํ•˜์ง€ ์•Š์€ N๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ N+1 ๋ฌธ์ œ๋ผ๊ณ  ํ•œ๋‹ค.

When ์–ธ์ œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

  • JPA Repository๋ฅผ ํ™œ์šฉํ•ด ์ธํ„ฐํŽ˜์ด์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ(Read ์‹œ)

Who ๋ˆ„๊ฐ€ ๋ฐœ์ƒ์‹œํ‚ค๋Š”๊ฐ€?

  • 1:N ๋˜๋Š” N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ๋ฐœ์ƒ

How ์–ด๋–ค ์ƒํ™ฉ์— ๋ฐœ์ƒ๋˜๋Š”๊ฐ€?

  • JPA Fetch ์ „๋žต์ด EAGER ์ „๋žต์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ
  • JPA Fetch ์ „๋žต์ด LAZY ์ „๋žต์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ์ดํ›„์— ์—ฐ๊ด€ ๊ด€๊ณ„์ธ ํ•˜์œ„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ค์‹œ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ

Why ์™œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

  • JPA Repository๋กœ find ์‹œ ์‹คํ–‰ํ•˜๋Š” ์ฒซ ์ฟผ๋ฆฌ์—์„œ ํ•˜์œ„ ์—”ํ‹ฐํ‹ฐ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ , ํ•˜์œ„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ถ”๊ฐ€๋กœ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์—.
  • JPQL์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ธ€๋กœ๋ฒŒ Fetch ์ „๋žต์„ ๋ฌด์‹œํ•˜๊ณ  JPQL๋งŒ ๊ฐ€์ง€๊ณ  SQL์„ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์—.

EAGER(์ฆ‰์‹œ ๋กœ๋”ฉ)์ธ ๊ฒฝ์šฐ

  1. JPQL์—์„œ ๋งŒ๋“  SQL์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ
  2. ์ดํ›„ JPA์—์„œ Fetch ์ „๋žต์„ ๊ฐ€์ง€๊ณ  ํ•ด๋‹น ๋ฐ์ดํ„ฐ์˜ ์—ฐ๊ด€ ๊ด€๊ณ„์ธ ํ•˜์œ„ ์—”ํ‹ฐํ‹ฐ๋“ค์„ ์ถ”๊ฐ€ ์กฐํšŒ
  3. 2๋ฒˆ ๊ณผ์ •์œผ๋กœ N + 1 ๋ฌธ์ œ ๋ฐœ์ƒ

User(์‚ฌ์šฉ์ž)์™€ Order(์ฃผ๋ฌธ)์€ ํ˜„์žฌ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋กœ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•œ๋‹ค. User ์—”ํ‹ฐํ‹ฐ๋ฅผ findAll()๋ฅผ ์ด์šฉํ•ด ๋ชจ๋“  ์‚ฌ์šฉ์ž๋“ค์„ ์กฐํšŒํ•˜๋ ค๊ณ  ํ• ๋•Œ, ์›๋ž˜๋Š” ์‚ฌ์šฉ์ž๋“ค์— ๊ด€ํ•œ ๋‚ด์šฉ๋งŒ ์กฐํšŒ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ User์˜ ์—ฐ๊ด€๊ด€๊ณ„ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์กฐํšŒ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ ์‚ฌ์šฉ์ž๋งˆ๋‹ค ์—ฐ๊ด€๋œ Order ์—”ํ‹ฐํ‹ฐ๋„ ์กฐํšŒ๊ฐ€ ํ•จ๊ป˜ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ 5๋ช…์ผ๋•Œ, ์‚ฌ์šฉ์ž ์กฐํšŒ์— ๋Œ€ํ•œ ๋‚ด์šฉ(1) + ๊ฐ 5๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ฃผ๋ฌธ Entity์— ๋Œ€ํ•œ ๋‚ด์šฉ(5)์œผ๋กœ 1+5 ๋กœ ์กฐํšŒ๊ฐ€ ๋˜์–ด 1+N์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ, ์—ฐ๊ด€๊ด€๊ณ„๊นŒ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์กฐํšŒํ•˜๋Š” ์ฆ‰์‹œ๋กœ๋”ฉ์ผ ๊ฒฝ์šฐ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  1. findAll()์„ ํ•œ ์ˆœ๊ฐ„ select u from User u์ด๋ผ๋Š” JPQL ๊ตฌ๋ฌธ์ด ์ƒ์„ฑ๋˜๊ณ  ํ•ด๋‹น ๊ตฌ๋ฌธ์„ ๋ถ„์„ํ•œ select * from user ์ด๋ผ๋Š” SQL์ด ์ƒ์„ฑ๋˜์–ด ์‹คํ–‰๋œ๋‹ค.
  2. DB์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ User ์—”ํ‹ฐํ‹ฐ์˜ ์ธ์Šคํ„ด์Šค๋“ค์„ ์ƒ์„ฑํ•œ๋‹ค.
  3. User์™€ ์—ฐ๊ด€๋˜์–ด ์žˆ๋Š” Order ๋„ ๋กœ๋”ฉ์„ ํ•ด์•ผ ํ•œ๋‹ค.
  4. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์—ฐ๊ด€๋œ User๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  5. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—†๋‹ค๋ฉด 2์—์„œ ๋งŒ๋“ค์–ด์ง„ User ์ธ์Šคํ„ด์Šค๋“ค ๊ฐœ์ˆ˜์— ๋งž๊ฒŒ select * from order where User_id = ? ์ด๋ผ๋Š” SQL ๊ตฌ๋ฌธ์ด ์ƒ์„ฑ๋œ๋‹ค. ( N+1 ๋ฐœ์ƒ )

LAZY(์ง€์—ฐ ๋กœ๋”ฉ)์ธ ๊ฒฝ์šฐ

  1. JPQL์—์„œ ๋งŒ๋“  SQL์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ
  2. JPA์—์„œ Fetch ์ „๋žต์„ ๊ฐ€์ง€์ง€๋งŒ, ์ง€์—ฐ ๋กœ๋”ฉ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ ์กฐํšŒ๋Š” ํ•˜์ง€ ์•Š์Œ
  3. ํ•˜์ง€๋งŒ, ํ•˜์œ„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์ž‘์—…ํ•˜๊ฒŒ ๋˜๋ฉด ์ถ”๊ฐ€ ์กฐํšŒ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ตญ N + 1 ๋ฌธ์ œ ๋ฐœ์ƒ

ํ•„์š”ํ• ๋•Œ๋งŒ ์—ฐ๊ด€๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ User ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ• ๋•Œ๋Š” N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ, ํ•˜์œ„ ์—”ํ‹ฐํ‹ฐ์ธ Order๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ, Order์—”ํ‹ฐํ‹ฐ๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— User๋ฅผ ์กฐํšŒํ•˜๊ณ  ๋‚˜์„œ Order๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ์ฆ‰์‹œ๋กœ๋”ฉ๊ณผ ๊ฐ™์ด N+1๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

  1. findAll()์„ ํ•œ ์ˆœ๊ฐ„select u from User u ์ด๋ผ๋Š” JPQL ๊ตฌ๋ฌธ์ด ์ƒ์„ฑ๋˜๊ณ  ํ•ด๋‹น ๊ตฌ๋ฌธ์„ ๋ถ„์„ํ•œ select * from user ์ด๋ผ๋Š” SQL์ด ์ƒ์„ฑ๋˜์–ด ์‹คํ–‰๋œ๋‹ค.
  2. DB์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ User ์—”ํ‹ฐํ‹ฐ์˜ ์ธ์Šคํ„ด์Šค๋“ค์„ ์ƒ์„ฑํ•œ๋‹ค.
  3. ์ฝ”๋“œ ์ค‘์—์„œ User ์˜ Order ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋Š” ์‹œ์ ์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์—ฐ๊ด€๋œ Order๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค
  4. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—†๋‹ค๋ฉด 2์—์„œ ๋งŒ๋“ค์–ด์ง„ User ์ธ์Šคํ„ด์Šค๋“ค ๊ฐœ์ˆ˜์— ๋งž๊ฒŒ select * from order where User_id = ? ์ด๋ผ๋Š” SQL ๊ตฌ๋ฌธ์ด ์ƒ์„ฑ๋œ๋‹ค. ( N+1 ๋ฐœ์ƒ )

๐Ÿ“ŒN+1 ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1. Fetch join

N+1 ์ž์ฒด๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š” ํ•œ์ชฝ ํ…Œ์ด๋ธ”๋งŒ ์กฐํšŒํ•˜๊ณ  ์—ฐ๊ฒฐ๋œ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์€ ๋”ฐ๋กœ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
๋ฏธ๋ฆฌ ๋‘ ํ…Œ์ด๋ธ”์„ JOIN ํ•˜์—ฌ ํ•œ ๋ฒˆ์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์• ์ดˆ์— N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.
ex) select * from owner left join cat on cat.owner_id = owner.id

๊ทธ๋ ‡๊ฒŒ ๋‚˜์˜จ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด FetchJoin ๋ฐฉ๋ฒ•์ด๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” jpaRepository์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ  JPQL๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

@Query("select o from Owner o join fetch o.cats")
List<Owner> findAllJoinFetch();


๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ฟผ๋ฆฌ๊ฐ€ 1๋ฒˆ๋งŒ ๋ฐœ์ƒํ•˜๊ณ  ๋ฏธ๋ฆฌ owner์™€ pet ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ธ(Inner Join)ํ•ด์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Fetch Join(ํŒจ์น˜ ์กฐ์ธ)์˜ ๋‹จ์ 

  • ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ •ํ•ด๋†“์€ FetchType์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. Fetch Join์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐ์ดํ„ฐ ํ˜ธ์ถœ ์‹œ์ ์— ๋ชจ๋“  ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— FetchType์„ Lazy๋กœ ํ•ด๋†“๋Š”๊ฒƒ์ด ๋ฌด์˜๋ฏธํ•˜๋‹ค.
  • ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฌธ์œผ๋กœ ๊ฐ€์ ธ์˜ค๋‹ค ๋ณด๋‹ˆ ํŽ˜์ด์ง• ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

2. @Entity Graph

@EntityGraph ์˜ attributePaths์— ์ฟผ๋ฆฌ ์ˆ˜ํ–‰์‹œ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ํ•„๋“œ๋ช…์„ ์ง€์ •ํ•˜๋ฉด Lazy๊ฐ€ ์•„๋‹Œ Eager ์กฐํšŒ๋กœ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค. Fetch join๊ณผ ๋™์ผํ•˜๊ฒŒ JPQL์„ ์‚ฌ์šฉํ•˜์—ฌ query ๋ฌธ์„ ์ž‘์„ฑํ•˜๊ณ  ํ•„์š”ํ•œ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ EntityGraph์— ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Fetch join๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ join ๋ฌธ์ด outer join์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

@EntityGraph(attributePaths = "cats")
@Query("select o from Owner o")
List<Owner> findAllEntityGraph();


๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ฟผ๋ฆฌ๊ฐ€ 1๋ฒˆ๋งŒ ๋ฐœ์ƒํ•˜๊ณ  ๋ฏธ๋ฆฌ owner์™€ pet ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ธ(outerJoin)ํ•ด์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

3. Fetch Join๊ณผ EntityGraph ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•  ์ 

Fetch Join๊ณผ EntityGraph๋Š” JPQL์„ ์‚ฌ์šฉํ•˜์—ฌ JOIN๋ฌธ์„ ํ˜ธ์ถœํ•œ๋‹ค๋Š” ๊ณตํ†ต์ ์ด ์žˆ๋‹ค. ๋˜ํ•œ, ๊ณตํ†ต์ ์œผ๋กœ ์นดํ…Œ์‹œ์•ˆ ๊ณฑ(Cartesian Product)์ด ๋ฐœ์ƒํ•˜์—ฌ Owner์˜ ์ˆ˜๋งŒํผ Cat์ด ์ค‘๋ณต ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ค‘๋ณต๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ปฌ๋ ‰์…˜์— ์กด์žฌํ•˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

โ€ป ์นดํ…Œ์‹œ์•ˆ ๊ณฑ
๋‘ ํ…Œ์ด๋ธ” ์‚ฌ์ด์— ์œ ํšจ join ์กฐ๊ฑด์„ ์ ์ง€ ์•Š์•˜์„ ๋•Œ ํ•ด๋‹น ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ ๊ฒฐํ•ฉํ•˜์—ฌ ํ…Œ์ด๋ธ”์— ์กด์žฌํ•˜๋Š” ํ–‰ ๊ฐฏ์ˆ˜๋ฅผ ๊ณฑํ•œ๋งŒํผ์˜ ๊ฒฐ๊ณผ ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ

์ถœ์ฒ˜

https://velog.io/@tmdwns1521/DAO%EC%99%80-ORM-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
https://velog.io/@jeong-god/ORM%EA%B3%BC-JPA%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
https://victorydntmd.tistory.com/195
https://ittrue.tistory.com/254
https://s-y-130.tistory.com/184
https://jh2021.tistory.com/21
https://velog.io/@pdy000726/fetch-join-vs-EntityGraph

profile
CS ๊ณต๋ถ€๋ฅผ ํ•ด๋ด…์‹œ๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€