Skip to content

[๐ŸŒฑ JPA ๋ฐฉํƒˆ์ถœ ์˜ˆ์•ฝ ๋Œ€๊ธฐ] ์–ด์…”(๋ฐ•์ง„์šฐ) ๋ฏธ์…˜ ์ œ์ถœํ•ฉ๋‹ˆ๋‹ค.#557

Open
sinequanonn wants to merge 2 commits into
woowacourse:sinequanonnfrom
sinequanonn:jpa-waiting2
Open

[๐ŸŒฑ JPA ๋ฐฉํƒˆ์ถœ ์˜ˆ์•ฝ ๋Œ€๊ธฐ] ์–ด์…”(๋ฐ•์ง„์šฐ) ๋ฏธ์…˜ ์ œ์ถœํ•ฉ๋‹ˆ๋‹ค.#557
sinequanonn wants to merge 2 commits into
woowacourse:sinequanonnfrom
sinequanonn:jpa-waiting2

Conversation

@sinequanonn

Copy link
Copy Markdown

JPA ์ „ํ™˜ ๋ฐ ์˜ˆ์•ฝ ๋Œ€๊ธฐ ๊ธฐ๋Šฅ

JdbcTemplate ๊ธฐ๋ฐ˜ ๋ฐฉํƒˆ์ถœ ์˜ˆ์•ฝ ์ฝ”๋“œ๋ฅผ JPA๋กœ ์ „ํ™˜ํ•˜๊ณ , ๊ทธ ์œ„์— ๊ฐ ๋‹จ๊ณ„๋ณ„ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

๋‹จ๊ณ„๋ณ„ ๋„๋‹ฌ ์ง€์ 

  • 0๋‹จ๊ณ„: ๋ธŒ๋žœ์น˜ ๋ถ„๋ฆฌ ๋ฐ ๊ธฐ์กด ๋™์ž‘ ํ™•์ธ ํ›„ ์ˆ˜์ • ๋ฐฉ์•ˆ ๊ณ ๋ฏผ
  • 1๋‹จ๊ณ„: ๋ชจ๋“  ๋„๋ฉ”์ธ(Theme, ReservationTime, Reservation, Holiday) JpaEntity๋กœ ์ „ํ™˜, ManyToOne ๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ด€ ๊ด€๊ณ„ ๋งคํ•‘, JpaRepository๋กœ ๊ต์ฒด(Jdbc ์ž”์žฌ ์ œ๊ฑฐํ•˜๊ธฐ), ๋™์‹œ์„ฑ์šฉ reservation_slot๋งŒ raw SQL ์œ ์ง€
  • 2๋‹จ๊ณ„: GET /reservations-mine ๋‚ด ์˜ˆ์•ฝ ๋ชฉ๋ก ์กฐํšŒ (๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌ๋กœ)
  • 3๋‹จ๊ณ„: ์˜ˆ์•ฝ ๋Œ€๊ธฐ ์š”์ฒญ, ์ทจ์†Œ(/waitings), N๋ฒˆ์งธ ๋Œ€๊ธฐ ํ‘œ์‹œ, N+1 ๋ฌธ์ œ ํ•ด์†Œ
  • 4๋‹จ๊ณ„: ๊ด€๋ฆฌ์ž ๋Œ€๊ธฐ ๋ชฉ๋ก ์กฐํšŒ, ์ทจ์†Œ, ์˜ˆ์•ฝ ์ทจ์†Œ ์‹œ ์ž๋™ ์Šน๊ฒฉ

๋ฐœํ–‰ SQL ๋ฐœ์ทŒ

N๋ฒˆ์งธ ๋Œ€๊ธฐ - ์„œ๋ธŒ์ฟผ๋ฆฌ์™€ fetch join ์‚ฌ์šฉ

select r.id, ..., t.*, rt.*,
  (select count(w.id) from reservation w
   where w.theme_id=t.id and w.time_id=rt.id
     and w.status='WAITING' and w.created_at < r.created_at)
from reservation r
join theme t on t.id=r.theme_id
join reservation_time rt on rt.id=r.time_id
where r.name=? order by r.id
  • ์ˆœ๋ฒˆ์„ ์ธ๋ฉ”๋ชจ๋ฆฌ๋กœ ๊ณ„์‚ฐํ•˜๊ณ  EAGER๋กœ ์—ฐ๊ด€ ๋กœ๋”ฉํ–ˆ์„ ๋•Œ๋Š” ๊ฐ ํ•˜๋‚˜์˜ ์˜ˆ์•ฝ๋งˆ๋‹ค Theme๊ณผ Time์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ”๋‹ค
  • JPQL๊ณผ fetch join์„ ํ™œ์šฉํ•ด์„œ ํ•œ ๋ฐฉ ์ฟผ๋ฆฌ๋กœ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ํ–ˆ๋‹ค.

๋ง์„ค์ธ ๊ฒฐ์ •

  1. ์ž๋™ ์Šน์ธ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„
    : ์ทจ์†Œ์™€ ์Šน๊ฒฉ์„ ๋‹จ์ผ @Transactional๋กœ ๋ฌถ์—ˆ๋‹ค. "์ทจ์†Œ ์„ฑ๊ณต, ์Šน๊ฒฉ ์‹คํŒจ"๋ฅผ ํ—ˆ์šฉํ•˜๋ ค๋ฉด ์ปค๋ฐ‹ ํ›„ ์ด๋ฒคํŠธ๋กœ ๋ถ„๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ทจ์†Œ์™€ ์Šน๊ฒฉ ์‚ฌ์ด์— ๋™์‹œ์„ฑ์„ ๊ณ ๋ คํ•ด์•ผ ํ•  ๊ฒŒ ๋งŽ์•„์กŒ๋‹ค. ๋ˆ„๊ฐ€ ์‹คํŒจ ๋น„์šฉ์„ ์ง€๋Š”๊ฐ€๋ฅผ ๋”ฐ์ ธ๋ณด๊ณ  ์›์ž์„ฑ์„ ์„ ํƒํ–ˆ๋‹ค.
  2. JPQL fetch join vs @EntityGraph
    : ๋‘˜ ๋‹ค ์—ฐ๊ด€์„ ํ•œ ์ฟผ๋ฆฌ๋กœ ๋‹น๊ฒจ์˜ค์ง€๋งŒ, ํ‘œํ˜„๋ ฅ์ด ๋‹ค๋ฅด๋‹ค. ๋‹จ์ˆœํ•œ ์—ฐ๊ด€๋งŒ ํ•จ๊ป˜ ๋กœ๋”ฉํ•˜๋ฉด ๋˜๋Š” ์กฐํšŒ๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌ์— ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ ์ฒ˜๋ฆฌํ•˜๊ณ , n๋ฒˆ์งธ ๋Œ€๊ธฐ์™€ ๊ฐ™์ด ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ์ˆœ๋ฒˆ์„ ๊ณ„์‚ฐํ•ด์•ผ ํ•˜๋Š” (์ฆ‰, ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๋ฅผ ํˆฌ์˜ํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ํ•„์š”ํ•  ๋•Œ)๋Š” JPQL์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.

ํ”๋“ค๋ฆฐ ํ•œ ์žฅ๋ฉด

์ง€์—ฐ ๋กœ๋”ฉ๊ณผ ์ฆ‰์‹œ ๋กœ๋”ฉ์„ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. findByName ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌ๋ฅผ ์“ธ ๋•Œ, EAGER๋ฉด ์ฆ‰์‹œ ๋กœ๋”ฉ์ด๋‹ˆ๊น JPA๊ฐ€ ํ•œ ๋ฐฉ join ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ์ค„ ์•Œ์•˜๋‹ค. ํ•˜์ง€๋งŒ ๋กœ๊ทธ๋ฅผ ๋ณด๋‹ˆ๊น EAGER์—ฌ๋„ ์˜ˆ์•ฝ์„ ๋จผ์ € ์กฐํšŒํ•˜๊ณ  ์—ฐ๊ด€์€ ๊ฑด๋งˆ๋‹ค ๋ณ„๋„ SELECT๊ฐ€ ๋‚˜๊ฐ€๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์•Œ๊ณ ๋ณด๋‹ˆ id๋กœ ์กฐํšŒ(findById)ํ•  ๋•Œ๋งŒ ์กฐ์ธ์œผ๋กœ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๊ณ , id๊ฐ€ ์•„๋‹Œ ์กฐํšŒ๋Š” EAGER์—ฌ๋„ ์—ฐ๊ด€๋งˆ๋‹ค ๋ณ„๋„ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€ N+1์ด ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ์ฆ‰ ์ฆ‰์‹œ/์ง€์—ฐ์€ ์–ธ์ œ ๋กœ๋”ฉํ•˜๋А๋ƒ์— ํฌ์ปค์Šค๋ฅผ ๋งž์ถ”๊ณ , ์–ด๋–ป๊ฒŒ๋Š” ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์ฟผ๋ฆฌ์—์„œ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋ ค๋ฉด join fetch๋‚˜ entityGraph๋ฅผ ์ง์ ‘ ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ์ตํ˜”๋‹ค.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant