๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ–ฅ๏ธ ๋ญ”๊ฐ€๋ญ”๊ฐ€ํ”„๋กœ์ ํŠธ/โœ๏ธ TIL

[TIL] ํ”„๋กœ์ ํŠธ 5์ผ์ฐจ.. ๋ฐฐ์†ก ๊ด€๋ จ ๋กœ์ง ๋” ์ƒ๊ฐํ•ด๋ณด๊ธฐ..

by carrot0911 2025. 5. 23.

๐ŸŒž ์˜ค๋Š˜์€ ์–ด๋–ค ํ•˜๋ฃจ์˜€์ง€..

MVP ๊ตฌํ˜„ํ•œ ๊ฒƒ ์ค‘์—์„œ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์„ ์ฑ„์›Œ ๋„ฃ๊ณ  GlobalExceptionHandler๋ฅผ ํ™œ์šฉํ•ด์„œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋“ค์„ ์ˆ˜์ •ํ–ˆ๋‹ค.

ํƒ๋ฐฐ์‚ฌ, ์ถœ๊ณ ์ง€(๋ฌผ๋ฅ˜์„ผํ„ฐ), ๋ฐฐ์†ก, ์†ก์žฅ ๋„๋ฉ”์ธ์„ ์ฒœ์ฒœํžˆ ๋‘˜๋Ÿฌ๋ณด๋ฉด์„œ ๋น ์ง„ ๋กœ์ง์€ ์ถ”๊ฐ€ํ•˜๊ณ , ์ข€ ๋” ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •์„ ์ง„ํ–‰ํ–ˆ๋‹ค.
๊ทธ ๊ณผ์ •์—์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ์žฌ๊ณ  ๋ถ€๋ถ„์„ ๋งก๊ธฐ๋กœ ํ•ด์„œ ์–ด๋””์— ์žฌ๊ณ  ๊ด€๋ จ ๋กœ์ง์ด ๋“ค์–ด๊ฐ€๋ฉด ์ข‹์„์ง€ ์ƒ๊ฐ๋„ ํ•ด๋ดค๋‹ค.

์•„์ง ๋กœ์ง์ด ํ™•์‹คํ•˜๊ฒŒ ๋จธ๋ฆฌ์— ์žกํžˆ์ง€ ์•Š์•„์„œ ๊ณ„์† ์ƒ๊ฐ์„ ํ•ด๋ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

๐Ÿ’ก ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๋‚ด์šฉ์€ ๋ญ๊ฐ€ ์žˆ๋”๋ผ..?!

๐Ÿ’ก findById() vs getReferenceById() ์ฐจ์ด ์™„์ „ ์ •๋ฆฌ

Spring Data JPA๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ findById()์™€ getReferenceById()๊ฐ€ ์žˆ๋‹ค.
๋‘ ๋ฉ”์„œ๋“œ๋Š” ์œ ์‚ฌํ•ด ๋ณด์ด์ง€๋งŒ ๋™์ž‘ ๋ฐฉ์‹๊ณผ ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ์ด ๋‹ค๋ฅด๋‹ค.

โœ… ๊ธฐ๋ณธ ์„ค๋ช…

๋ฉ”์„œ๋“œ ์„ค๋ช…
findById() ์ฆ‰์‹œ DB์—์„œ ์กฐํšŒํ•˜์—ฌ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜. Optional<T> ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜๋จ
getReferenceById() ํ”„๋ก์‹œ ๊ฐ์ฒด ๋ฐ˜ํ™˜. ์‹ค์ œ ํ•„๋“œ์— ์ ‘๊ทผํ•˜๋Š” ์ˆœ๊ฐ„ DB์—์„œ ์กฐํšŒ๋จ (Lazy Loading)

โœ… ์‚ฌ์šฉ ์˜ˆ์‹œ

๐Ÿ“Œ findById()

Courier courier = courierRepository.findById(id)
    .orElseThrow(() -> new RuntimeException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํƒ๋ฐฐ์‚ฌ์ž…๋‹ˆ๋‹ค."));
  • DB์— ์ฆ‰์‹œ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋จ
  • ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฐ”๋กœ ์˜ˆ์™ธ๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ์Œ

๐Ÿ“Œ getReferenceById()

Courier courier = courierRepository.getReferenceById(id);
  • ์ฟผ๋ฆฌ๊ฐ€ ๋ฐ”๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์Œ
  • ์‹ค์ œ๋กœ courier.getName()์ฒ˜๋Ÿผ ํ•„๋“œ์— ์ ‘๊ทผํ•  ๋•Œ DB ์กฐํšŒ๊ฐ€ ์ผ์–ด๋‚จ
  • ํ•ด๋‹น ID๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, ๊ทธ๋•Œ EntityNotFoundException ๋ฐœ์ƒ

โœ… ์ฐจ์ด์  ๋น„๊ตํ‘œ

ํ•ญ๋ชฉ findById() getReferenceById()

ํ•ญ๋ชฉ findById() getReferenceById()
๋ฐ˜ํ™˜ ๊ฐ์ฒด Optional<T> ํ”„๋ก์‹œ ๊ฐ์ฒด (T)
DB ์ ‘๊ทผ ์‹œ์  ์ฆ‰์‹œ ์ฟผ๋ฆฌ ์‹คํ–‰ ์‹ค์ œ ํ•„๋“œ ์ ‘๊ทผ ์‹œ์ 
์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ์  ์กฐํšŒ ์ฆ‰์‹œ orElseThrow() ํ•„๋“œ ์ ‘๊ทผ ์‹œ์ 
ํŠธ๋žœ์žญ์…˜ ํ•„์š” ์—ฌ๋ถ€ ์—†์–ด๋„ ๊ฐ€๋Šฅ ๋ฐ˜๋“œ์‹œ ํ•„์š” (Lazy Loading)
์ฃผ์š” ์‚ฌ์šฉ ์šฉ๋„ ์—”ํ‹ฐํ‹ฐ ์‹ค์ œ ์กฐํšŒ ์ฐธ์กฐ๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ (ex. ์™ธ๋ž˜ ํ‚ค ๋งคํ•‘ ๋“ฑ)

โœ… ์‚ฌ์šฉ ์‹œ์  ์ถ”์ฒœ

์ƒํ™ฉ ์ถ”์ฒœ ๋ฉ”์„œ๋“œ ์ด์œ 

์ƒํ™ฉ ์ถ”์ฒœ ๋ฉ”์„œ๋“œ ์ด์œ 
์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ findById() ์•ˆ์ •์ ์ด๊ณ  ๋ช…ํ™•ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹จ์ˆœํžˆ ๋งคํ•‘ํ•  ๋•Œ (ํ•„๋“œ ์ ‘๊ทผ ์•ˆ ํ•  ๋•Œ) getReferenceById() ํ”„๋ก์‹œ๋งŒ ์ฃผ์ž…ํ•˜๋ฏ€๋กœ ์„ฑ๋Šฅ ํšจ์œจ์ 
์กด์žฌ ์—ฌ๋ถ€๋งŒ ๋จผ์ € ํ™•์ธํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ existsById() + getReferenceById() ๋‹จ, ์ฟผ๋ฆฌ 2๋ฒˆ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์กฐ์ •

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

  • getReferenceById()๋Š” ํŠธ๋žœ์žญ์…˜์ด ์œ ์ง€๋˜์ง€ ์•Š์œผ๋ฉด LazyInitializationException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • getReferenceById()๋กœ ๋ฐ˜ํ™˜๋œ ํ”„๋ก์‹œ๋Š” ํ•„๋“œ ์ ‘๊ทผ ์‹œ์ ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋””๋ฒ„๊น…์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค.
  • ์‹ค๋ฌด์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„ findById().orElseThrow() ๋ฐฉ์‹์ด ๋” ์•ˆ์ •์ ์ด๋‹ค.

โœจ ๊ฒฐ๋ก 

  • ์ผ๋ฐ˜์ ์ธ CRUD ์ฒ˜๋ฆฌ์—์„œ๋Š” findById() ์‚ฌ์šฉ์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜์ž.
  • ์„ฑ๋Šฅ์„ ๋ฏธ์„ธํ•˜๊ฒŒ ์ตœ์ ํ™”ํ•˜๊ฑฐ๋‚˜, ์—ฐ๊ด€ ๊ด€๊ณ„๋งŒ ๋งบ๊ณ  ํ•„๋“œ ์ ‘๊ทผ์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” getReferenceById()๋„ ์œ ํšจํ•˜๋‹ค.

๐Ÿ”– ๋งˆ๋ฌด๋ฆฌ ์š”์•ฝ

โ— findById()๋Š” ์ง€๊ธˆ ๋‹น์žฅ DB์—์„œ ๊บผ๋‚ด์˜ค๋Š” ๋ฐฉ์‹
โ— getReferenceById()๋Š” "ํ•„์š”ํ•˜๋ฉด ๊ฐ€์ ธ์˜ฌ๊ฒŒ"๋ผ๋Š” ์ง€์—ฐ ๋กœ๋”ฉ ๋ฐฉ์‹

 

๐Ÿ”’ ๋ฝ ๊ฒฝํ•ฉ (Lock Contention)์ด๋ž€?

โœ… ๊ฐœ๋…

  • "์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ๊ฐ™์€ ์ž์›(๋ ˆ์ฝ”๋“œ)์„ ์ž ๊ทธ๋ ค ํ•˜๋ฉด์„œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋Š” ํ˜„์ƒ"
  • ๋Œ€ํ‘œ์ ์œผ๋กœ ๋น„๊ด€์  ๋ฝ(FOR UPDATE) ์‚ฌ์šฉ ์‹œ ๋ฐœ์ƒ

โœ… ์˜ˆ์‹œ ์ƒํ™ฉ

  • ์ƒํ’ˆ ์žฌ๊ณ ๊ฐ€ 5๊ฐœ์ธ๋ฐ 100๋ช…์ด ๋™์‹œ์— ๋ฐฐ์†ก์„ ์š”์ฒญํ•จ
  • ์ฒซ ๋ฒˆ์งธ ํŠธ๋žœ์žญ์…˜์ด ๋ฝ์„ ์žก๋Š” ๋™์•ˆ ๋‚˜๋จธ์ง€๋Š” ๋Œ€๊ธฐ
  • ์ด๋กœ ์ธํ•ด ์‹œ์Šคํ…œ ์‘๋‹ต ์ง€์—ฐ, ํƒ€์ž„์•„์›ƒ, ์ปค๋„ฅ์…˜ ๊ฒฝํ•ฉ์ด ๋ฐœ์ƒ

โŒ ๋ฌธ์ œ์ 

  • ๋Œ€๊ธฐ ์‹œ๊ฐ„ ์ฆ๊ฐ€ → ์‚ฌ์šฉ์ž ์‘๋‹ต ์ง€์—ฐ
  • ๋ฝ ๋Œ€๊ธฐ ์ค‘ ํŠธ๋žœ์žญ์…˜์ด ๋„ˆ๋ฌด ์˜ค๋ž˜ ๋จธ๋ฌด๋ฅด๋ฉด LockTimeoutException ๋ฐœ์ƒ ๊ฐ€๋Šฅ
  • ๋ฝ ๋Œ€๊ธฐ ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด DB ์ปค๋„ฅ์…˜ ๊ณ ๊ฐˆ ์œ„ํ—˜

๐Ÿ”ง ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  • ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ์ตœ์†Œํ™”: ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์€ ๋ฝ ๋ฐ–์—์„œ ์ฒ˜๋ฆฌ
  • ๋ฝ ํƒ€์ž„์•„์›ƒ ์„ค์ • (innodb_lock_wait_timeout)
  • ์ž์›๋ณ„๋กœ ๋ถ„๋ฆฌ๋œ ๋ฝ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ถฉ๋Œ ๋ถ„์‚ฐ (ex. ์ƒํ’ˆ ID ๋‹จ์œ„๋กœ ๋ฝ)
  • ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ ๋‚™๊ด€์  ๋ฝ ๋˜๋Š” ๋ฉ”์‹œ์ง€ ํ ๋ฐฉ์‹์œผ๋กœ ๊ตฌ์กฐ ์ „ํ™˜ ๊ณ ๋ ค

 

๐Ÿ—“๏ธ ๋‚ด์ผ์€ ๋ญ ํ•˜์ง€?!