Spring/JPA

@Transactional을 μ‚¬μš©ν•˜λŠ” 이유

Huijinn 2024. 12. 7. 21:44

@Transactional의 κΈ°λ³Έ κ°œλ…

μ •μ˜

@Transactional은 μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬μ—μ„œ μ œκ³΅ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ, ν•΄λ‹Ή λ©”μ†Œλ“œλ‚˜ ν΄λž˜μŠ€μ—μ„œ μ‹€ν–‰λ˜λŠ” DB μž‘μ—…(INSERT, UPDATE, DELETE λ“±)을 ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜ λ²”μœ„ μ•ˆμ—μ„œ μ²˜λ¦¬ν•˜λ„λ‘ ν•˜λŠ” 역할을 ν•œλ‹€.

κΈ°λŠ₯

λͺ¨λ“  DB 연산을 ν•˜λ‚˜μ˜ μ›μžμ  λ‹¨μœ„λ‘œ λ¬Άμ–΄ 성곡 μ‹œ 일괄 컀밋, μ‹€νŒ¨ μ‹œ 일괄 둀백을 톡해 데이터 무결성과 일관성을 보μž₯ν•œλ‹€.


@Transactional을 μ‚¬μš©ν•˜λŠ” 이유

1. μ›μžμ„±(Atomicity) 보μž₯

λ©”μ†Œλ“œ μ‹€ν–‰ 쀑 ν•˜λ‚˜μ˜ μž‘μ—…μ΄λΌλ„ μ‹€νŒ¨ν•˜λ©΄, ν•΄λ‹Ή λ©”μ†Œλ“œ λ‚΄ λͺ¨λ“  λ³€κ²½ 사항을 λ‘€λ°±ν•œλ‹€. 예λ₯Ό λ“€μ–΄ INSERT ν›„ UPDATEμ—μ„œ μ˜ˆμ™Έ λ°œμƒ μ‹œ, INSERT λ˜ν•œ μ·¨μ†Œλ˜μ–΄ DB μƒνƒœκ°€ μ΄μ „μœΌλ‘œ λ³΅μ›λœλ‹€.

2. 일관성(Consistency) 보μž₯

ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜ μ•ˆμ—μ„œ 데이터 변경이 μ΄λ£¨μ–΄μ§€λ―€λ‘œ, DB μƒνƒœμ˜ 일관성이 μœ μ§€λœλ‹€.

3. 격리성(Isolation) 확보

νŠΈλžœμž­μ…˜ 섀정에 따라 λ‹€λ₯Έ νŠΈλžœμž­μ…˜κ³Όμ˜ 격리 μˆ˜μ€€μ„ μ‘°μ •ν•˜μ—¬ λ™μ‹œμ„± 문제λ₯Ό 쀄일 수 μžˆλ‹€.

4. λͺ…ν™•ν•œ νŠΈλžœμž­μ…˜ 경계

μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ @Transactional을 ν™œμš©ν•˜λ©΄ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 λ‹¨μœ„λ‘œ νŠΈλžœμž­μ…˜ 경계λ₯Ό λͺ…ν™•νžˆ μ„€μ •ν•  수 μžˆμ–΄ μœ μ§€λ³΄μˆ˜κ°€ νŽΈλ¦¬ν•˜λ‹€.


μ–Έμ œ @Transactional을 λΆ™μ—¬μ•Ό ν• κΉŒ?

1. 데이터 λ³€κ²½ 둜직 (INSERT, UPDATE, DELETE)

μ—¬λŸ¬ DB λ³€κ²½ μž‘μ—…μ„ ν•˜λ‚˜μ˜ λ‹¨μœ„λ‘œ λ¬Άκ³  싢을 λ•Œ @Transactional을 μ μš©ν•΄ μ›μžμ„±μ„ 보μž₯ν•˜λŠ” 것이 μΌλ°˜μ μ΄λ‹€.

2. 쑰회 μ „μš© 둜직 (SELECT)

λ‹¨μˆœ μ‘°νšŒμ—μ„œλŠ” ν•„μˆ˜μ μ΄μ§€ μ•ŠμœΌλ‚˜, μ§€μ—° λ‘œλ”©(Lazy Loading)을 ν™œμš©ν•˜κ±°λ‚˜ @Transactional(readOnly = true)λ₯Ό 톡해 더티 체킹을 μƒλž΅ν•˜λŠ” λ“±μ˜ μ΅œμ ν™”λ₯Ό ν•  수 μžˆλ‹€.

3. μ„œλΉ„μŠ€ λ ˆμ΄μ–΄

DAO(Repository) 호좜과 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ κ²°ν•©ν•˜λŠ” μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ νŠΈλžœμž­μ…˜μ„ κ΄€λ¦¬ν•˜λŠ” 것이 일반적인 νŒ¨ν„΄μ΄λ‹€.


@Transactional을 무쑰건 λΆ™μ—¬μ•Ό ν• κΉŒ?

  • "무쑰건"은 μ•„λ‹ˆλ‹€. λΆˆν•„μš”ν•˜κ²Œ λͺ¨λ“  λ©”μ†Œλ“œμ— 뢙이면 였히렀 μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•  수 μžˆλ‹€.
  • λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 상 "이 λ‘œμ§μ€ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ μ²˜λ¦¬ν•΄μ•Ό ν•œλ‹€"λŠ” λͺ…ν™•ν•œ 기쀀이 μžˆμ„ λ•Œλ§Œ μ‚¬μš©ν•œλ‹€.
  • λ‹¨μˆœν•œ insert ν•œ 번만 μˆ˜ν–‰ν•˜λŠ” λ©”μ†Œλ“œλΌλ„, ν–₯ν›„ ν™•μž₯ κ°€λŠ₯μ„±μ΄λ‚˜ λͺ…ν™•ν•œ νŠΈλžœμž­μ…˜ 경계 섀정을 μœ„ν•΄ 뢙일 μˆ˜λ„ 있고, μƒμœ„ κ³„μΈ΅μ—μ„œ 이미 νŠΈλžœμž­μ…˜μ„ κ΄€λ¦¬ν•œλ‹€λ©΄ μƒλž΅ν•  μˆ˜λ„ μžˆλ‹€.

νŠΈλžœμž­μ…˜μ΄ μ—†μœΌλ©΄ μ–΄λ–€ 일이 λ°œμƒν• κΉŒ?

  • μ—λŸ¬λ‚˜ μ˜ˆμ™Έ λ°œμƒ μ‹œ 이미 μ‹€ν–‰λœ DB λ³€κ²½(예: INSERT)은 되돌릴 수 μ—†λ‹€. λΆ€λΆ„λ§Œ DB에 λ°˜μ˜λ˜μ–΄ 데이터 무결성을 μžƒμ„ 수 μžˆλ‹€.
  • LazyInitializationException, TransactionRequiredException λ“± νŠΈλžœμž­μ…˜μ΄ 없을 경우 λ°œμƒν•˜λŠ” μ˜ˆμ™Έλ‘œ 인해 정상적인 μ—”ν‹°ν‹° 관리가 μ–΄λ €μšΈ 수 μžˆλ‹€.

@Transactional(readOnly = true)

  • 읽기 μ „μš© λͺ¨λ“œλ‘œ μ„€μ •ν•˜λ©΄ Hibernate와 같은 ORM이 더티 체킹을 μˆ˜ν–‰ν•˜μ§€ μ•Šκ±°λ‚˜ μ΅œμ†Œν™”ν•˜μ—¬ μ„±λŠ₯ μ΅œμ ν™”λ₯Ό μ œκ³΅ν•  수 μžˆλ‹€.
  • DB 변경이 μ—†λ‹€λŠ” 보μž₯이 μžˆμ„ 경우, Flushλ‚˜ Lock νšλ“ 과정을 μƒλž΅ν•˜μ—¬ μžμ› μ‚¬μš©μ„ 쀄일 수 μžˆλ‹€.

정리

  • @Transactional은 μŠ€ν”„λ§ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ νŠΈλžœμž­μ…˜ 경계λ₯Ό λͺ…ν™•νžˆ μ„€μ •ν•˜κ³ , DB λ³€κ²½ μ‹œμ˜ μ•ˆμ •μ„±κ³Ό μ›μžμ„±μ„ ν™•λ³΄ν•˜λŠ” 핡심 도ꡬ이닀.
  • 상황에 따라 readOnly 속성 ν™œμš©, μ μ ˆν•œ 계측(주둜 Service 레벨)μ—μ„œμ˜ μ„€μ •, ν•„μš”ν•  λ•Œλ§Œ μ‚¬μš©ν•˜λŠ” μ „λž΅μ„ 톡해 효율적인 데이터 접근을 κ΅¬ν˜„ν•  수 μžˆλ‹€.
  • 컀λ„₯μ…˜ 관리 및 μ΅œμ ν™”(컀λ„₯μ…˜ ν’€, readOnly νŠΈλžœμž­μ…˜)와 κ²°ν•©ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯κ³Ό μ•ˆμ •μ„±μ„ ν•œ 단계 높일 수 μžˆλ‹€.