Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ configurations {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
Expand Down
612 changes: 398 additions & 214 deletions docs/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## 3. 0๋‹จ๊ณ„ - ๊ธฐ๋ณธ ์ฝ”๋“œ ์ค€๋น„ํ•˜๊ธฐ

ํ‰๊ฐ€ ๋Œ€๊ธฐ

์ œ์ถœ ์™„๋ฃŒ2026. 6. 17. ์ œ์ถœ

# 0๋‹จ๊ณ„: ๊ธฐ๋ณธ ์ฝ”๋“œ ์ค€๋น„

`spring-roomescape-waiting` ์ €์žฅ์†Œ์˜ **๋ณธ์ธ ๋ธŒ๋žœ์น˜**์— ๋ฐฉํƒˆ์ถœ ๋ฏธ์…˜์—์„œ ์ž‘์—…ํ•œ ์ฝ”๋“œ๊ฐ€ ๊ทธ๋Œ€๋กœ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ ์œ„์— JPA ์ „ํ™˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. **0๋‹จ๊ณ„๋Š” UI ๋™์ž‘ ํ™•์ธ์„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค** โ€” 1๋‹จ๊ณ„๊ฐ€ ๋๋‚˜์•ผ UI ์—ฐ๋™์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

> **๋“ค์–ด๊ฐ€๊ธฐ ์ „ ์ž๊ธฐ ์ง„๋‹จ**

Q. ๋ณธ์ธ ๋ธŒ๋žœ์น˜์˜ ๋ฐฉํƒˆ์ถœ ๋ฏธ์…˜ ์ฝ”๋“œ๋Š” ๋™์ž‘ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ธ๊ฐ€์š”? ๋ณธ์ธ ์ฝ”๋“œ์˜ ๊ตฌ์กฐ๋ฅผ ํ•œ๋ˆˆ์— ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

ํ˜„์žฌ ์ „์ฒด ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ•˜๊ณ  ์ •์ƒ ์ž‘๋™ํ•˜๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ์˜ˆ์•ฝ, ์˜ˆ์•ฝ ๋‚ ์งœ, ์˜ˆ์•ฝ ์‹œ๊ฐ„, ํ…Œ๋งˆ, ์˜ˆ์•ฝ ๋Œ€๊ธฐ ๊ธฐ๋Šฅ์„ ์ค‘์‹ฌ์œผ๋กœ Controller, Service, Repository ๊ณ„์ธต์ด ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž ์ธ์ฆ/์ธ๊ฐ€๋Š” ์—†๊ณ , ์˜ˆ์•ฝ๊ณผ ์˜ˆ์•ฝ ๋Œ€๊ธฐ ์กฐํšŒ๋Š” name ์š”์ฒญ ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ์€ /admin/\*\* ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธํ„ฐ์…‰ํ„ฐ๋กœ ์ ‘๊ทผ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. DB ์ ‘๊ทผ์€ JdbcTemplate, ์ง์ ‘ ์ž‘์„ฑํ•œ SQL, parameter binding, RowMapper๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Repository ๊ตฌํ˜„์ฒด๊ฐ€ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๋„๋ฉ”์ธ ๊ฐ์ฒด๋Š” Reservation, ReservationDate, ReservationTime, Theme, WaitingReservation์ด๋ฉฐ, ReservationSlot๊ณผ ReservationSlotResolver๊ฐ€ ๋‚ ์งœ/์‹œ๊ฐ„/ํ…Œ๋งˆ ์กฐํ•ฉ์˜ ์˜ˆ์•ฝ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ธฐ์ค€์„ JUnit๊ณผ ํ…Œ์ŠคํŠธ ๋”๋ธ”๋กœ ํŠน์ • ๊ฐ์ฒด์˜ ์ฑ…์ž„๋งŒ ํ™•์ธํ•˜๋ฉด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ ๋ณด์•˜๊ณ , ๊ทธ ์ด์™ธ์˜ ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ์š”์†Œ์˜ ํ†ตํ•ฉ ๊ฒ€์ฆ์„ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” ๊ฒƒ๋“ค์€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋กœ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ตœ์šฐ์„ ์œผ๋กœ ํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. Domain์€ ๊ฐ์ฒด์˜ ํ•ต์‹ฌ ๊ทœ์น™๊ณผ ์œ ํšจ์„ฑ์„ ์ง€ํ‚ค๋Š” ์—ญํ• ์ด๋ผ๊ณ  ๋ณด๊ณ  ํ•ต์‹ฌ ๊ทœ์น™๊ณผ ๋ถˆ๋ณ€์‹์„ ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ–ˆ์Šต๋‹ˆ๋‹ค. Repository๋Š” DB ์ €์žฅ/์กฐํšŒ์™€ SQL ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์ด๋ผ๊ณ  ๋ณด๊ณ  ํ•ด๋‹น ๋ถ€๋ถ„์„ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋กœ ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. Service๋Š” ๋„๋ฉ”์ธ๊ณผ Repository๋ฅผ ์กฐํ•ฉํ•ด ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์„ ์ง€ํ‚ค๋Š” ์—ญํ• ์ด๋ผ๊ณ  ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ Fake Repository๋ฅผ ์‚ฌ์šฉํ•ด DB ์—†์ด ์˜ˆ์•ฝ ์ƒ์„ฑ, ์ค‘๋ณต ๋ฐฉ์ง€, ๋งˆ๊ฐ๋œ ์˜ˆ์•ฝ ์ œํ•œ ๊ฐ™์€ ๊ทœ์น™์„ ๊ฒ€์ฆํ–ˆ๊ณ , ์˜ˆ์•ฝ ๋Œ€๊ธฐ ์Šน๊ฒฉ๊ณผ ๋กค๋ฐฑ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ์ €์žฅ์†Œ์™€ ํŠธ๋žœ์žญ์…˜์ด ํ•„์š”ํ•œ ํ๋ฆ„์€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋กœ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. Controller๋Š” HTTP ์š”์ฒญ์„ ๊ฒ€์ฆํ•˜๊ณ  Service์— ์œ„์ž„ํ•œ ๋’ค ์ƒํƒœ ์ฝ”๋“œ์™€ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—ญํ• ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ MockMvc๋‚˜ RestAssured๋กœ ์š”์ฒญ ๊ฒ€์ฆ, ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ, JSON ์‘๋‹ต์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

## ์‹œ์ž‘์ 

์ด ์„ ํƒ๋ฏธ์…˜์€ `spring-roomescape-waiting`์˜ **๋ณธ์ธ ๋ธŒ๋žœ์น˜**์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ž๊ธฐ ์†์œผ๋กœ ๋งŒ๋“  SQL์ด ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋กœ ์–ด๋–ป๊ฒŒ ์˜ฎ๊ฒจ์ง€๋Š”์ง€ **์ง์ ‘ ๋น„๊ต**ํ•˜๋Š” ์ž๋ฆฌ๊ฐ€ ์ด ๋ฏธ์…˜์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

## 0๋‹จ๊ณ„ ์š”๊ตฌ์‚ฌํ•ญ
- ๋ณธ์ธ ๋ธŒ๋žœ์น˜์—์„œ ์ž‘์—…ํ•  ์ƒˆ ๋ธŒ๋žœ์น˜๋ฅผ ๋”ฐ๊ณ  ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. 1๋‹จ๊ณ„ ์ดํ›„์˜ ๋ณ€ํ™˜ diff๊ฐ€ ๊น”๋”ํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค.
- ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋ฏธ์…˜์ด ๋ณด๋ ค๋Š” "๋‚ด ๋ฐฉํƒˆ์ถœ ๋ฏธ์…˜ SQL์ด JPA๋กœ ์–ด๋–ป๊ฒŒ ์˜ฎ๊ฒจ์ง€๋Š”๊ฐ€"์˜ ๋น„๊ต ๋Œ€์ƒ์ด ํ๋ ค์ง‘๋‹ˆ๋‹ค.
- ๋™์ž‘ ํ™•์ธ: ๋ณธ์ธ ๋ธŒ๋žœ์น˜์˜ ๋ฐฉํƒˆ์ถœ ๋ฏธ์…˜ ๋™์ž‘์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

> 0๋‹จ๊ณ„๋Š” ํ‘ธ์‹œ ํ›„ PR์„ ์—ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ตœ์ข… PR(๋ฏธ์…˜ ์ข…๋ฃŒ ์‹œ) ๋ณธ๋ฌธ์— 0๋‹จ๊ณ„์˜ **์‹œ์ž‘ ๋ธŒ๋žœ์น˜ยท์ž‘์—… ๋ธŒ๋žœ์น˜**์™€ **์ด๋ฒˆ ๋ฏธ์…˜์—์„œ ๊ฑด๋“œ๋ฆด ๋ฒ”์œ„**๋ฅผ ํ•œ ๋‹จ๋ฝ์œผ๋กœ ์ ์Šต๋‹ˆ๋‹ค.

## ํ™•์ธ ๊ณผ์ œ

Q. ๋ฐฉํƒˆ์ถœ ๋ฏธ์…˜ ์ฝ”๋“œ ์ค‘ JPA ์ „ํ™˜์—์„œ ๊ฑด๋“œ๋ฆด ๋ถ€๋ถ„๊ณผ ๊ทธ๋Œ€๋กœ ๋‘˜ ๋ถ€๋ถ„์˜ ๊ฒฝ๊ณ„๋ฅผ ์ ์–ด์ฃผ์„ธ์š”. ๋ฌด์—‡์„ ๋ฐ”๊ฟ€ ์˜ˆ์ •์ด๊ณ  ๋ฌด์—‡์€ ์œ ์ง€ํ•  ์˜ˆ์ •์ธ๊ฐ€์š”?

JPA ์ „ํ™˜์—์„œ๋Š” JdbcTemplate ๊ธฐ๋ฐ˜ Repository ๊ตฌํ˜„์ฒด, ์ง์ ‘ ์ž‘์„ฑํ•œ SQL, RowMapper๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœ CRUD๋Š” Spring Data JPA Repository๋กœ ์ „ํ™˜ํ•˜๊ณ , ์˜ˆ์•ฝ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์กฐํšŒ, ์ธ๊ธฐ ํ…Œ๋งˆ ์กฐํšŒ, ์˜ˆ์•ฝ ๋Œ€๊ธฐ ์ˆœ๋ฒˆ ์กฐํšŒ์ฒ˜๋Ÿผ ์กฐ๊ฑด์ด ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋Š” ๊ธฐ์กด SQL์˜ ์˜๋ฏธ๋ฅผ ๋ณด์กดํ•˜๋ฉด์„œ JPQL์ด๋‚˜ ๋ณ„๋„ ์กฐํšŒ ์ „๋žต์„ ๊ฒ€ํ† ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. JPA ์ „ํ™˜ ๊ณผ์ •์—์„œ๋Š” ๊ธฐ์กด Repository ํ…Œ์ŠคํŠธ์™€ ์„œ๋น„์Šค ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘์ด ์œ ์ง€๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. Controller API ์ŠคํŽ™, Service์˜ ๊ธฐ์กด ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™, ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ๋ฆ„, ๊ด€๋ฆฌ์ž ํ† ํฐ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด, ํ˜„์žฌ ํŒจํ‚ค์ง€ ๊ตฌ์กฐ๋Š” ์œ ์ง€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๋‹จ๊ณ„์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ/์ธ๊ฐ€ ๊ตฌ์กฐ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค๊ฑฐ๋‚˜ UI ์—ฐ๋™์„ ํ™•์ธํ•˜์ง€ ์•Š๊ณ , ๊ธฐ์กด ๊ธฐ๋Šฅ์ด ์œ ์ง€๋˜๋Š” ๋ฒ”์œ„ ์•ˆ์—์„œ DB ์ ‘๊ทผ ๋ฐฉ์‹์„ JPA๋กœ ๋ฐ”๊พธ๋Š” ๋ฐ ์ง‘์ค‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
98 changes: 98 additions & 0 deletions docs/jpa-mission/1๋‹จ๊ณ„-JPA-์ „ํ™˜.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
## 4. 1๋‹จ๊ณ„ - JPA ์ „ํ™˜

ํ‰๊ฐ€ ๋Œ€๊ธฐ

์ œ์ถœ ์™„๋ฃŒ2026. 6. 21. ์ œ์ถœ

# 1๋‹จ๊ณ„: JPA ์ „ํ™˜

JdbcTemplate Repository๋ฅผ JPA Repository๋กœ ์ „๋ฉด ๊ต์ฒดํ•˜๊ณ , ๋„๋ฉ”์ธ ๊ฐ„ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋กœ ํ‘œํ˜„ํ•˜๋ฉฐ, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋™์ž‘์„ ์ง์ ‘ ๊ด€์ฐฐํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฏธ์…˜์—์„œ ๋ถ„๋Ÿ‰์ด ๊ฐ€์žฅ ํฐ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. ๋งคํ•‘ยท์—ฐ๊ด€๊ด€๊ณ„ยท์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•œ๊บผ๋ฒˆ์— ๋“ฑ์žฅํ•˜๋‹ˆ ํŽ˜์ด์Šค๋ฅผ ์žก์„ ๋•Œ ๊ฐ€์žฅ ๋ฌด๊ฑฐ์šด ๋‹จ๊ณ„๋กœ ์˜์‹ํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

> **๋“ค์–ด๊ฐ€๊ธฐ ์ „ ์ž๊ธฐ ์ง„๋‹จ**

Q. ๋ณธ์ธ ์ฝ”๋“œ์˜ Repository์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” SQL ํŒจํ„ด์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

Theme, ReservationTime, ReservationDate์ฒ˜๋Ÿผ ๋…๋ฆฝ์ ์ธ ๋„๋ฉ”์ธ์€ insert, select by id, find all, delete, exists ๊ฐ™์€ ๋‹จ์ˆœ SQL์ด ์ž์ฃผ ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Reservation๊ณผ WaitingReservation์€ reservation\_date, reservation\_time, theme ํ…Œ์ด๋ธ”์„ JOINํ•ด์„œ ํ•œ ๋ฒˆ์— ์กฐํšŒํ•œ ๋’ค, RowMapper์—์„œ ReservationDate, ReservationTime, Theme ๊ฐ์ฒด๋กœ ์ง์ ‘ ์กฐ๋ฆฝํ•˜๋Š” ํŒจํ„ด์ด ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.

Q. ๊ฐ์ฒด ์ฐธ์กฐ๋กœ ์˜ฎ๊ฒผ์„ ๋•Œ ๋” ์ž์—ฐ์Šค๋Ÿฌ์›Œ์ง€๋Š” ๊ณณ์€ ์–ด๋””์ธ๊ฐ€์š”?

๊ฐ์ฒด ์ฐธ์กฐ๋กœ ์˜ฎ๊ฒผ์„ ๋•Œ ๊ฐ€์žฅ ์ž์—ฐ์Šค๋Ÿฌ์›Œ์ง€๋Š” ๊ณณ์€ Reservation์ด ReservationDate, ReservationTime, Theme๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด DB ํ…Œ์ด๋ธ”์€ date\_id, time\_id, theme\_id ์™ธ๋ž˜ ํ‚ค๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ, Java ๋„๋ฉ”์ธ ๊ฐ์ฒด๋Š” ์ด๋ฏธ ๋‚ ์งœ, ์‹œ๊ฐ„, ํ…Œ๋งˆ๋ฅผ ๊ฐ์ฒด๋กœ ๋“ค๊ณ  ์žˆ์–ด ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘ํ•˜๋ฉด reservation.getTime().getStartAt(), reservation.getTheme().getName()์ฒ˜๋Ÿผ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋กœ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์ด ๋” ์ž์—ฐ์Šค๋Ÿฌ์›Œ์ง‘๋‹ˆ๋‹ค.
* * *

## 1-1. ๋งคํ•‘ ๋ณ€ํ™˜

๋‹ค๋ฅธ ํด๋ž˜์Šค์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค โ€” `Theme`, `ReservationTime` ๋“ฑ.

### ์š”๊ตฌ์‚ฌํ•ญ
- `build.gradle`: `spring-boot-starter-jdbc` โ†’ `spring-boot-starter-data-jpa` ๋Œ€์ฒด
- `@Entity`, `@Id`, `@GeneratedValue(strategy = IDENTITY)` ๋ถ€์—ฌ
- `JpaRepository<T, Long>` ์ธํ„ฐํŽ˜์ด์Šค ์ž‘์„ฑ, ๊ธฐ์กด JdbcTemplate ๊ธฐ๋ฐ˜ Repository ์ œ๊ฑฐ
- `KeyHolder`, `SimpleJdbcInsert` ๊ฐ™์€ JdbcTemplate ์ž”์žฌ ์ œ๊ฑฐ
- `application.properties` ๊ถŒ์žฅ ์„ค์ •:

```properties
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.ddl-auto=create-drop
spring.jpa.defer-datasource-initialization=true
```

> **์–‘์ชฝ ์‹œ๋„ ์‹œ ๋น„๊ต ๊ด€์ฐฐ ํฌ์ธํŠธ**: โ‘  ์‹œ์ž‘ ์‹œ ๋ฐœํ–‰๋˜๋Š” DDL์˜ ์ฐจ์ด โ‘ก ์žฌ์‹œ์ž‘ ์‹œ ๋ฐ์ดํ„ฐ ๋ณด์กด ์—ฌ๋ถ€ โ‘ข ์ปฌ๋Ÿผ๋ช…ยทํƒ€์ž…์„ entity๋กœ๋งŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š”์ง€. ์ด ์…‹์ด ์•ˆ ๋ณด์ด๋ฉด ๊ทธ๋ƒฅ ์–‘์ชฝ ๋‹ค ๋Œ๋ ค๋ดค์„ ๋ฟ ์ฐจ์ด๋Š” ๋ชป ๋ดค๋‹ค๋Š” ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

### ํ™•์ธ ๊ณผ์ œ

Q. ์˜ˆ์•ฝ ์ƒ์„ฑ ์‹œ ์ฝ˜์†”์— ์ฐํžˆ๋Š” INSERT SQL์ด ๋ฐฉํƒˆ์ถœ ๋ฏธ์…˜๊ณผ ์–ด๋–ป๊ฒŒ ๊ฐ™๊ณ  ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ๊ฐ€์š”?

\`\`\` Hibernate: insert into reservation (date\_id, name, theme\_id, time\_id, id) \`\`\` ๊ฐ™์€ ์ ์€ \`reservation\` ํ…Œ์ด๋ธ”์— ์˜ˆ์•ฝ์ž ์ด๋ฆ„, ๋‚ ์งœ id, ์‹œ๊ฐ„ id, ํ…Œ๋งˆ id๋ฅผ ์ €์žฅํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค DB์—๋Š” ์™ธ๋ž˜ ํ‚ค ๊ฐ’์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ ์€ ์ปฌ๋Ÿผ ์ˆœ์„œ๊ฐ€ ๊ธฐ์กด SQL์˜ \`name, date\_id, time\_id, theme\_id\`์™€ ๋‹ค๋ฅด๊ฒŒ \`date\_id, name, theme\_id, time\_id, id\`์ฒ˜๋Ÿผ ์ฐํ˜”๊ณ , \`id\`๋Š” \`IDENTITY\` ์ „๋žต์— ๋”ฐ๋ผ DB๊ฐ€ ์ƒ์„ฑํ•˜๋„๋ก \`default\`๋กœ ์ฒ˜๋ฆฌ๋œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ๋˜ ํ•˜๋‚˜์˜ ์ฐจ์ด๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ์ž…๋‹ˆ๋‹ค. JDBC์—์„œ๋Š” ์˜ˆ์•ฝ ์‚ญ์ œ ํ›„ ๊ฐ™์€ ์Šฌ๋กฏ์˜ ๋Œ€๊ธฐ๋ฅผ ์Šน๊ฒฉํ•  ๋•Œ DELETE๊ฐ€ ์ฆ‰์‹œ ์‹คํ–‰๋˜์–ด ๊ธฐ์กด ์Šฌ๋กฏ์ด ๋ฐ”๋กœ ๋น„์—ˆ์Šต๋‹ˆ๋‹ค. JPA์—์„œ๋Š” DELETE์™€ INSERT๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋ชจ์˜€๋‹ค๊ฐ€ flush ์‹œ์ ์— ๋™๊ธฐํ™”๋˜๋ฉด์„œ, Hibernate ๋‚ด๋ถ€ ActionQueue์— ๋”ฐ๋ผ์„œ INSERT๊ฐ€ ๋จผ์ € ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๊ณ , ์‹ค์ œ๋กœ ๋ฐœ์ƒํ•˜์—ฌ UNIQUE ์ œ์•ฝ์— ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜ˆ์•ฝ ์ทจ์†Œ/๋ณ€๊ฒฝ ํ›„ ๋Œ€๊ธฐ ์Šน๊ฒฉ ์ „์— \`reservationRepository.flush()\`๋ฅผ ํ˜ธ์ถœํ•ด ๊ธฐ์กด ์Šฌ๋กฏ์„ ๋จผ์ € DB์— ๋ฐ˜์˜ํ•˜๋„๋ก ์กฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
* * *

## 1-2. ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘

๋‹ค๋ฅธ ํด๋ž˜์Šค์— ์˜์กดํ•˜๋Š” ํด๋ž˜์Šค์— ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: `Reservation`์€ `Member`, `Theme`, `ReservationTime`์„ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

### ์š”๊ตฌ์‚ฌํ•ญ
- `@ManyToOne` + `@JoinColumn(name = "..._id")`๋กœ ๊ฐ์ฒด ์ฐธ์กฐ
- **๋‹จ๋ฐฉํ–ฅ์œผ๋กœ ์‹œ์ž‘**ํ•ฉ๋‹ˆ๋‹ค. ์–‘๋ฐฉํ–ฅ์ด ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๊ทธ๋•Œ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
- ์–‘๋ฐฉํ–ฅ ์‹œ๋„ ์‹œ **์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ** ๋ช…์‹œ, ๋ฌดํ•œ ์ง๋ ฌํ™” ๊ฐ€๋Šฅ์„ฑ ๊ฒ€ํ† .
- `cascade`, `orphanRemoval`์€ **ํ•„์š”ํ•ด์งˆ ๋•Œ๊นŒ์ง€ ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค**. ์ ์šฉํ•œ๋‹ค๋ฉด PR ๋ณธ๋ฌธ์— ๊ทธ ๊ทผ๊ฑฐ๋ฅผ ์ ์Šต๋‹ˆ๋‹ค.

> ์–‘๋ฐฉํ–ฅ ๋˜๋Š” cascade๋ฅผ ํ•œ ๋ฒˆ ์‹œ๋„ํ–ˆ๋‹ค๊ฐ€ ๋‹จ๋ฐฉํ–ฅ/์ œ๊ฑฐ๋กœ ํ›„ํ‡ดํ•˜๋Š” ์‚ฌ์ดํด์„ ์˜์‹์ ์œผ๋กœ ํ•œ ๋ฒˆ ๊ตด๋ ค๋ด…๋‹ˆ๋‹ค. ์‹œ๋„์™€ ํ›„ํ‡ด๋ฅผ ๊ธฐ๋ก์— ๋‚จ๊ธฐ๋Š” ๊ฒƒ์ด ์ฐจ์› B(์„ค๊ณ„ ํŒ๋‹จ)์˜ ๋„๋‹ฌ์ ์ž…๋‹ˆ๋‹ค.

### ํ™•์ธ ๊ณผ์ œ

Q. \`findById(reservationId).getTime().getStartAt()\`์ด ๋ฐœํ–‰ํ•˜๋Š” SQL์„ ์ ์–ด์ฃผ์„ธ์š”.

Hibernate: select r1\_0.id,r1\_0.date\_id,r1\_0.name,r1\_0.theme\_id,r1\_0.time\_id from reservation r1\_0 where r1\_0.id=? Hibernate: select rt1\_0.id,rt1\_0.start\_at from reservation\_time rt1\_0 where rt1\_0.id=?
* * *

## 1-3. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๊ด€์ฐฐ

์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋ณด๋‹ค **๊ด€์ฐฐ**ํ•ฉ๋‹ˆ๋‹ค. JPA๊ฐ€ ์ž๋™์œผ๋กœ ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ์ง์ ‘ ๋ด…๋‹ˆ๋‹ค.

**์ด ๋ฏธ์…˜์˜ ๋ณธ์งˆ 6๊ฐœ ์ค‘ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ฐ€์žฅ ๊นŠ์ด ๋ฐ•ํžˆ๋Š” ์ž๋ฆฌ์ž…๋‹ˆ๋‹ค.**

| ๊ด€์ฐฐ ๋Œ€์ƒ | ์–ด๋–ค ์ฝ”๋“œ๋กœ ํ™•์ธํ•˜๋Š”๊ฐ€ | ๋ฌด์—‡์„ ๋ณธ๋‹ค |
| --- | --- | --- |
| **dirty checking** | `@Transactional` ๋ฉ”์„œ๋“œ์—์„œ entity ํ•„๋“œ ์ˆ˜์ • ํ›„ save ๋ฏธํ˜ธ์ถœ | commit ์‹œ์ ์— UPDATE ์ž๋™ ๋ฐœํ–‰ |
| **1์ฐจ ์บ์‹œ** | ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜์—์„œ `findById` ๋‘ ๋ฒˆ ํ˜ธ์ถœ | ๋‘ ๋ฒˆ์งธ SELECT ์ƒ๋žต (1์ฐจ ์บ์‹œ ์ ์ค‘) |
| **์“ฐ๊ธฐ ์ง€์—ฐ** | `save` ํ˜ธ์ถœ ํ›„ `flush` ์ „ยทํ›„์˜ DB ์ƒํƒœ ๋น„๊ต | INSERT๊ฐ€ commit/flush ์‹œ์ ์— ์ผ๊ด„ ๋ฐœํ–‰ |
| **flush ์‹œ์ ** | ๋ช…์‹œ์  `flush` ํ˜ธ์ถœ / ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ / JPQL ์‹คํ–‰ ์ง์ „ | ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ โ†’ DB ๋™๊ธฐํ™” ํŠธ๋ฆฌ๊ฑฐ |
| **fetch ๊ธฐ๋ณธ๊ฐ’** | `@ManyToOne` vs `@OneToMany` ๋ฌด๋ช…์‹œ ์‹œ | EAGER vs LAZY ์ฐจ์ด |
| `LazyInitializationException` | ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ LAZY ํ•„๋“œ ์ ‘๊ทผ | ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋‹ซํžŒ ํ›„ ํ”„๋ก์‹œ ๋ฏธ์ดˆ๊ธฐํ™” |

### ๊ด€์ฐฐ ๊ณผ์ œ 1: ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์‹ ํ˜ธ ์บก์ฒ˜

์œ„ 6๊ฐœ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด ๊ธฐ๋ก์— ๋‚จ๊ธธ์ˆ˜๋ก ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์†์— ์žกํž™๋‹ˆ๋‹ค. ๊ด€์ฐฐ์„ ์ ์„ ๋•Œ ๋‹ค์Œ 4๊ฐ€์ง€๊ฐ€ ํ•จ๊ป˜ ์žˆ์œผ๋ฉด ๋ฏธ์…˜ ๋๋‚œ ํ›„ ๊ฐ€์žฅ ๊ฐ•ํ•œ ํšŒ์ƒ ์žฌ๋ฃŒ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

```
1. ์‹œ๋„ํ•œ ์ฝ”๋“œ
2. ์˜ˆ์ธกํ•œ SQL/๋™์ž‘
3. ์‹ค์ œ SQL/๋™์ž‘
4. ์™œ ๋‹ค๋ฅธ๊ฐ€
```

์˜ˆ์ธก๊ณผ ์‹ค์ œ ์‚ฌ์ด์˜ ๊ฐญ์ด ๋ณด์ด๋Š” ์ˆœ๊ฐ„์ด ๋ณธ ๋ฏธ์…˜์˜ ํ•ต์‹ฌ ํ•™์Šต ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

> ๊ด€์ฐฐ ๊ณผ์ œ 2(N+1๊ณผ fetch join ๋น„๊ต)๋Š” 3๋‹จ๊ณ„์—์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค. 1๋‹จ๊ณ„์—์„œ๋Š” LazyInit์„ ๋งŒ๋‚˜๋Š” ๊ฒƒ์œผ๋กœ๋„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๊ฒฝ๊ณ„๊ฐ€ ๋ณด์ž…๋‹ˆ๋‹ค.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## 5. 2๋‹จ๊ณ„ - ๋‚ด ์˜ˆ์•ฝ ๋ชฉ๋ก

ํ‰๊ฐ€ ๋Œ€๊ธฐ

์ œ์ถœ ์™„๋ฃŒ2026. 6. 22. ์ œ์ถœ

# 2๋‹จ๊ณ„: ๋‚ด ์˜ˆ์•ฝ ๋ชฉ๋ก ์กฐํšŒ ๊ธฐ๋Šฅ

๋‚ด ์˜ˆ์•ฝ ๋ชฉ๋ก ์กฐํšŒ API๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. **์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ ๋„์ž…์˜ ๋ฒฝ**์„ ๋งŒ๋‚˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

> **๋“ค์–ด๊ฐ€๊ธฐ ์ „ ์ž๊ธฐ ์ง„๋‹จ**

Q. ๋‚ด ์˜ˆ์•ฝ ๋ชฉ๋ก ์กฐํšŒ๋ฅผ ํ’€ ๋•Œ, ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌ(\`findByMemberId\`)์™€ JPQL(\`@Query\`) ์ค‘ ์–ด๋А ์ชฝ์ด ๋จผ์ € ๋– ์˜ค๋ฅด๋‚˜์š”? ๊ทธ ์ง๊ฐ์˜ ๊ทผ๊ฑฐ๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?

์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํžˆ \`findByName\`์œผ๋กœ ์˜ˆ์•ฝ์„ ์กฐํšŒํ•œ ๋’ค Java ์ฝ”๋“œ์—์„œ ์ง€๋‚œ ์˜ˆ์•ฝ์„ ์ œ์™ธํ•˜๋Š” ๋ฐฉ์‹๋„ ๋– ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์š”๊ตฌ์‚ฌํ•ญ์€ ํ™”๋ฉด์— ์œ ํšจํ•œ ์˜ˆ์•ฝ ๋ชฉ๋ก๋งŒ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด๊ณ , ์œ ํšจ ์—ฌ๋ถ€๋Š” ์˜ˆ์•ฝ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์ฒ˜๋Ÿผ DB๊ฐ€ ์ด๋ฏธ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ’์œผ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ชจ๋“  ์˜ˆ์•ฝ์„ ๊ฐ€์ ธ์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ•„ํ„ฐ๋งํ•˜๊ธฐ๋ณด๋‹ค๋Š” DB์—์„œ ๋จผ์ € ์กฐ๊ฑด์„ ๊ฑธ์–ด ๊ฐ€์ ธ์˜ค๋Š” ํŽธ์ด ๋” ์ ์ ˆํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ด ์กฐํšŒ๋Š” ๋‹จ์ˆœํžˆ ์ด๋ฆ„์œผ๋กœ๋งŒ ์ฐพ๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜ ์ดํ›„ ์˜ˆ์•ฝ์ด๊ฑฐ๋‚˜, ์˜ค๋Š˜ ์˜ˆ์•ฝ์ด๋ผ๋ฉด ํ˜„์žฌ ์‹œ๊ฐ„ ์ดํ›„์ธ ์˜ˆ์•ฝ๋งŒ ์กฐํšŒํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋‚ ์งœ์™€ ์‹œ๊ฐ„ ์กฐ๊ฑด์ด ํ•จ๊ป˜ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์‘๋‹ต์„ ๋งŒ๋“ค ๋•Œ ์˜ˆ์•ฝ์˜ ๋‚ ์งœ, ์‹œ๊ฐ„, ํ…Œ๋งˆ์— ์ ‘๊ทผํ•˜๋ฏ€๋กœ LAZY ์—ฐ๊ด€๊ด€๊ณ„์—์„œ N+1์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ๋„ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง€๊ธˆ ๊ธฐ์ค€์œผ๋กœ๋Š” ์กฐ๊ฑด์˜ ์˜๋„๋ฅผ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚ด๊ธฐ ์œ„ํ•ด JPQL์ด ๋จผ์ € ๋– ์˜ค๋ฆ…๋‹ˆ๋‹ค. ๋‹ค๋งŒ JPQL์„ ์“ด๋‹ค๊ณ  N+1์ด ์ž๋™์œผ๋กœ ํ•ด๊ฒฐ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ, ์‘๋‹ต ์ƒ์„ฑ์— ํ•„์š”ํ•œ ์—ฐ๊ด€ ๊ฐ์ฒด๋Š” \`@EntityGraph\`๋กœ ํ•จ๊ป˜ ๋กœ๋”ฉํ•˜๋Š” ๋ฐฉํ–ฅ์ด ๋” ์ ์ ˆํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

## ์š”๊ตฌ์‚ฌํ•ญ

### API
- `GET /reservations-mine` โ€” ๋ณธ์ธ์˜ ์˜ˆ์•ฝ ๋ชฉ๋ก

### ํ™•์ธ ๊ณผ์ œ

Q. ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌยทJPQL ์ค‘ ์–ด๋А ๊ฒƒ์„ ์ผ๋‚˜์š”?

์ €๋Š” JPQL(\`@Query\`)๊ณผ \`@EntityGraph\`๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. JPQL์€ ์˜ˆ์•ฝ ๋‚ ์งœ๊ฐ€ ์˜ค๋Š˜ ์ดํ›„์ด๊ฑฐ๋‚˜, ์˜ค๋Š˜ ์˜ˆ์•ฝ์ด๋ผ๋ฉด ํ˜„์žฌ ์‹œ๊ฐ„ ์ดํ›„์ธ ์˜ˆ์•ฝ๋งŒ ์กฐํšŒํ•œ๋‹ค๋Š” ์กฐ๊ฑด์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌ๋กœ๋„ ์–ด๋А ์ •๋„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‚ ์งœ์™€ ์‹œ๊ฐ„ ์กฐ๊ฑด์ด ํ•จ๊ป˜ ๋ฌถ์ด๋Š” ์ˆœ๊ฐ„ ๋ฉ”์„œ๋“œ๋ช…์ด ๊ธธ์–ด์ง€๊ณ  ์˜๋„๊ฐ€ ํ๋ ค์ง„๋‹ค๊ณ  ๋А๊ผˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ ๋กœ๋”ฉ์€ JPQL์˜ \`join fetch\`๊ฐ€ ์•„๋‹ˆ๋ผ \`@EntityGraph\`๋กœ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด API์˜ ์‘๋‹ต์—๋Š” ๋‚ ์งœ, ์‹œ๊ฐ„, ํ…Œ๋งˆ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ์—ฐ๊ด€ ๊ฐ์ฒด๋ฅผ ํ•จ๊ป˜ ๋กœ๋”ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ €๋Š” ์กฐํšŒ ์กฐ๊ฑด๊ณผ ๋กœ๋”ฉ ๋ฒ”์œ„๋ฅผ ํ•œ JPQL ์•ˆ์— ๋ชจ๋‘ ๋„ฃ๊ธฐ๋ณด๋‹ค๋Š”, JPQL์€ ์กฐ๊ฑด์„ ํ‘œํ˜„ํ•˜๊ณ  \`@EntityGraph\`๋Š” ํ•„์š”ํ•œ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋ฅผ ํ‘œํ˜„ํ•˜๋„๋ก ๋‚˜๋ˆ„๋Š” ํŽธ์ด ๋™์ž‘ ์˜๋„, ๋ณ€๊ฒฝ์— ๊ฐ•ํ•œ ๊ตฌ์กฐ, ๊ฐ€๋…์„ฑ ์ธก๋ฉด์—์„œ ๋” ๋‚ซ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

Q. ๊ทธ ๊ฒฐ์ •์˜ ํ•œ๊ณ„๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?

์ด ๊ฒฐ์ •์˜ ํ•œ๊ณ„๋Š” JPQL๊ณผ \`@EntityGraph\`๊ฐ€ ๋ชจ๋‘ ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜์ด๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์—”ํ‹ฐํ‹ฐ ํ•„๋“œ๋ช…์ด ๋ณ€๊ฒฝ๋˜๋ฉด Java ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ฐ”๋กœ ์žกํžˆ์ง€ ์•Š๊ณ , ์‹คํ–‰ ์‹œ์ ์ด๋‚˜ ์ฟผ๋ฆฌ ๊ฒ€์ฆ ์‹œ์ ์— ์˜ค๋ฅ˜๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ JPQL๊ณผ \`@EntityGraph\`๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š” ์—ญํ• ์„ ๋ถ„๋ฆฌํ•ด์„œ ์ฝ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ์กฐ๊ฑด์€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ฒ˜๋Ÿผ ์„ ํ˜•์ ์ธ ๊ตฌ์กฐ๋ณด๋‹ค JPQL์˜ ๊ด„ํ˜ธ์™€ ์กฐ๊ฑด์‹์œผ๋กœ ํ‘œํ˜„ํ•˜๋Š” ํŽธ์ด ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด N+1์„ ์ค„์ด๊ธฐ ์œ„ํ•œ ๋กœ๋”ฉ ๋ฒ”์œ„๋Š” \`@EntityGraph\`๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด, ์กฐํšŒ ์กฐ๊ฑด๊ณผ ๊ฐ์ฒด ๋กœ๋”ฉ ์ฑ…์ž„์„ ๋”ฐ๋กœ ๋ณผ ์ˆ˜ ์žˆ์–ด ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์ง„๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง•์ด ํ•„์š”ํ•ด์งˆ ๊ฒฝ์šฐ์—๋Š” ๋‹ค์‹œ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ์ฒ˜๋Ÿผ \`ManyToOne\` ์—ฐ๊ด€ ๊ฐ์ฒด๋ฅผ ํ•จ๊ป˜ ๋กœ๋”ฉํ•˜๋Š” ์ •๋„๋Š” ๋น„๊ต์  ์•ˆ์ „ํ•˜์ง€๋งŒ, \`OneToMany\` ๊ฐ™์€ ์ปฌ๋ ‰์…˜์„ ํ•จ๊ป˜ ๋กœ๋”ฉํ•˜๋ฉด row ์ค‘๋ณต๊ณผ count query ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง•์ด ๋“ค์–ด์˜ค๋ฉด ์‹ค์ œ SQL๊ณผ count query๋ฅผ ํ™•์ธํ•˜๋ฉด์„œ ์กฐํšŒ ๋ฐฉ์‹์„ ๋‹ค์‹œ ์ ๊ฒ€ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
Loading