๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โœ๏ธ Today I Learned(TIL)/์ŠคํŒŒ๋ฅดํƒ€ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„

[ TIL ] JPA ์‹ฌํ™”_Day 4

by carrot0911 2025. 1. 17.

์˜ค๋Š˜ ํ•œ ๊ณต๋ถ€ ๐Ÿง 

ํ•„์ˆ˜ ๊ณผ์ œ ์‹œ์ž‘

  • Level 1
    • @Transactional์˜ ์ดํ•ด
      • ํ˜„์žฌ ๊ธฐ๋ณธ์ ์œผ๋กœ TodoService์˜ ๋ชจ๋“  ๋กœ์ง์ด @Transactional(readOnly = true)๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค.
      • ๊ทธ๋ž˜์„œ saveTodo( ) ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋„ ๊ฐ™์€ ์„ค์ •์ด ๋“ค์–ด๊ฐ€์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋‹ค.
      • DB๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋”ฐ๋กœ @Transactional ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ค˜์•ผ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค.
    • JWT์˜ ์ดํ•ด

๊ถ๊ธˆํ–ˆ๋˜ ๋‚ด์šฉ

๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ ์œ„์— ๋”ฐ๋กœ @Transactional์„ ๋ถ™์—ฌ์ฃผ๋ฉด ๋˜์ง€ ์•Š์„๊นŒ? ์™œ ์ „์ฒด ์ ์šฉ์„ ํ•˜๋Š” ๊ฑฐ์ง€??

@Transactional(readOnly = true)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์กฐํšŒ์šฉ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด์„œ ์„ฑ๋Šฅ์ƒ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ

์ผ๋ฐ˜์ ์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•ด์„œ DB์— ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ๊ณผ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ํŠธ๋žœ์žญ์…˜์„ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์‹ค์ˆ˜๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด์„œ ์ผ๊ด€์„ฑ์„ ์œ„๋ฐ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์•„์ง„๋‹ค. ์กฐํšŒํ•˜๋Š” ๋ฉ”์„œ๋“œ์—์„œ๋„ ์ผ๊ด€์„ฑ์„ ์œ„๋ฐ˜ํ•˜๊ฒŒ ๋  ์šฐ๋ ค๊ฐ€ ์žˆ๊ธฐ์— ํ•ญ์ƒ ์ฃผ์˜๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

๊ฐ€๋…์„ฑ ํ–ฅ์ƒ

์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋Š” @Transactional(readOnly = true)๊ฐ€ ์„ค์ •๋œ ๋ฉ”์„œ๋“œ๊ฐ€ DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋œ๋‹ค.

// 1
@Transactional
public Member getMember(Long memberId) {
    return memberRepository.findById(memberId)
    	.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
}

// 2
@Transactional(readOnly = true)
public Member getMember(Long memberId) {
    return memberRepository.findById(memberId)
	    .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
}

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

JPA์˜ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ณ€๊ฒฝ ๊ฐ์ง€์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค.
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” Entity ์กฐํšŒ ์‹œ ์ดˆ๊ธฐ ์ƒํƒœ์— ๋Œ€ํ•œ Snapshot์„ ์ €์žฅํ•œ๋‹ค. ํŠธ๋žœ์žญ์…˜์ด Commit ๋  ๋•Œ, ์ดˆ๊ธฐ ์ƒํƒœ์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๋Š” Snapshot๊ณผ Entity์˜ ์ƒํƒœ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์— ๋Œ€ํ•ด update query๋ฅผ ์ƒ์„ฑํ•ด ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์ €์žฅํ•œ๋‹ค.
๊ทธ ํ›„, ์ผ๊ด„์ ์œผ๋กœ ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” SQL Query๋ฅผ flush ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŠธ๋žœ์žญ์…˜์„ Commit ํ•จ์œผ๋กœ์จ ์šฐ๋ฆฌ๊ฐ€ update์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ Entity์˜ ์ˆ˜์ •์ด ์ด๋ฃจ์–ด์ง„๋‹ค.
์ด๋ฅผ ๋ณ€๊ฒฝ ๊ฐ์ง€(Dirty Checking)์ด๋ผ๊ณ  ํ•œ๋‹ค.
readOnly = true๋ฅผ ์„ค์ •ํ•˜๊ฒŒ ๋˜๋ฉด ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋Š” JPA์˜ ์„ธ์…˜ ํ”Œ๋Ÿฌ์‰ฌ ๋ชจ๋“œ๋ฅผ MANUAL๋กœ ์„ค์ •ํ•œ๋‹ค.

MANAUL ๋ชจ๋“œ๋Š” ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜๋™์œผ๋กœ flush๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด flush๊ฐ€ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋Š” ๋ชจ๋“œ์ด๋‹ค.

ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๊ฐ•์ œ๋กœ flush()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ํ•œ, ์ˆ˜์ • ๋‚ด์—ญ์— ๋Œ€ํ•ด DB์— ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
์ด๋กœ ์ธํ•ด ํŠธ๋žœ์žญ์…˜ Commit ์‹œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ž๋™์œผ๋กœ flush ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์กฐํšŒ์šฉ์œผ๋กœ ๊ฐ€์ ธ์˜จ Entity์˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ˆ˜์ •์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋˜ํ•œ, ReadOnly = true๋ฅผ ์„ค์ •ํ•˜๊ฒŒ ๋˜๋ฉด JPA๋Š” ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์กฐํšŒํ•˜๋Š” Entity๋Š” ์กฐํšŒ์šฉ์ž„์„ ์ธ์‹ํ•˜๊ณ  ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ์œ„ํ•œ Snapshot์„ ๋”ฐ๋กœ ๋ณด๊ด€ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ ˆ์•ฝ๋˜๋Š” ์„ฑ๋Šฅ์ƒ ์ด์  ์—ญ์‹œ ์กด์žฌํ•œ๋‹ค.

 

์˜ค๋Š˜ ํ•˜๋ฃจ ์ •๋ฆฌ โœ๏ธ

๋˜ ์ผ์ฃผ์ผ์ด ์ง€๋‚˜๊ฐ”๋‹ค..
์ด๋ฒˆ ์ฃผ์—๋Š” ์ง‘์ค‘๋ ฅ์ด ์ตœ์ €๋กœ ๋–จ์–ด์กŒ๋˜ ํ•œ์ฃผ์˜€๋‹ค.. ๊ณ„์† ๋”ด์ง“์„ ํ•˜๊ฒŒ ๋˜๊ณ  ๊ฐ•์˜ ๋“ค์„ ๋•Œ ์ง‘์ค‘๋„ ์•ˆ๋˜๊ณ ..

์ฃผ๋ง ๋™์•ˆ ๋ฆฌํ”„๋ ˆ์‰ฌ ์ข€ ํ•ด์„œ ๋‹ค์‹œ ์ •์‹  ์ฐจ๋ฆฌ๊ณ  ์—ด์‹ฌํžˆ ํ•ด๋ด์•ผ์ง€.
์ž˜ ์‰ฌ๊ณ  ์—ด์‹ฌํžˆ ๊ณต๋ถ€ํ•˜๊ณ .. ์ปจ๋””์…˜ ๊ด€๋ฆฌ ์ž˜ํ•˜์ž!!

 

์ฃผ๋ง ๊ณ„ํš โฐ

  • ํ•„์ˆ˜๊ณผ์ œ ์ง„ํ–‰
  • ์ถ”๊ฐ€ ๊ณต๋ถ€
  • ๋ธ”๋กœ๊ทธ ์ •๋ฆฌ