Transaction, @Transactional

νŠΈλžœμž­μ…˜μ΄λž€?

νŠΈλžœμž­μ…˜μ€ 'ν•˜λ‚˜μ˜ 논리적인 μž‘μ—… λ‹¨μœ„'λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€. 핡심은 All or Nothingμž…λ‹ˆλ‹€.

  • Commit: μž‘μ—…μ΄ μ„±κ³΅μ μœΌλ‘œ λλ‚˜μ„œ κ²°κ³Όλ₯Ό ν™•μ • μ§“λŠ” 것.

  • Rollback: μž‘μ—… 쀑 ν•˜λ‚˜λΌλ„ μ‹€νŒ¨ν•˜λ©΄, λͺ¨λ“  μž‘μ—…μ„ μ·¨μ†Œν•˜κ³  처음 μƒνƒœλ‘œ λ˜λŒλ¦¬λŠ” 것.

[μ˜ˆμ‹œ: 홍길동이 μž„κΊ½μ •μ—κ²Œ 3,000원을 μ΄μ²΄ν•œλ‹€λ©΄?]

이체 λ‘œμ§μ€ 크게 4λ‹¨κ³„λ‘œ μ§„ν–‰λ©λ‹ˆλ‹€.

  1. 홍길동 κ³„μ’Œ 쑰회 (μž”μ•‘ 10,000원)

  2. 홍길동 κ³„μ’Œμ—μ„œ 3,000원 차감 (μž”μ•‘ 7,000원)

  3. μž„κΊ½μ • κ³„μ’Œ 쑰회 (μž”μ•‘ 10,000원)

  4. μž„κΊ½μ • κ³„μ’Œμ— 3,000원 μΆ”κ°€ (μž”μ•‘ 13,000원)

[문제 상황] λ§Œμ•½ 2λ²ˆκΉŒμ§€ μ„±κ³΅ν•˜κ³ , 3λ²ˆμ—μ„œ "μ—†λŠ” κ³„μ’Œλ²ˆν˜Έμž…λ‹ˆλ‹€"라며 μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ μ–΄λ–»κ²Œ λ κΉŒμš”? νŠΈλžœμž­μ…˜μ΄ μ—†λ‹€λ©΄ μž„κΊ½μ • λˆμ€ κ·ΈλŒ€λ‘œμΈλ° 홍길동 λˆμ€ 쀄어든, 돈이 μ‚¬λΌμ§€λŠ” 사고가 λ°œμƒν•©λ‹ˆλ‹€. 이것이 λ°”λ‘œ 데이터 일관성이 κΉ¨μ§€λŠ” μƒν™©μž…λ‹ˆλ‹€.

Spring @Transactional μ μš©ν•˜κΈ°

μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬μ—μ„œλŠ” @Transactional μ–΄λ…Έν…Œμ΄μ…˜ ν•˜λ‚˜λ§Œ 뢙이면, λ³΅μž‘ν•œ 컀밋/λ‘€λ°± 처리λ₯Ό λŒ€μ‹ ν•΄ μ€λ‹ˆλ‹€.

[μ‹œλ‚˜λ¦¬μ˜€]

  • 정상 이체: Account A -> Account B (성곡)

  • 이체 μ‹€νŒ¨: Account A -> Account 999(μ—†λŠ” κ³„μ’Œ) (쀑간에 μ—λŸ¬ λ°œμƒ)

[1. νŠΈλžœμž­μ…˜μ΄ μ—†λŠ” 경우]

κ²°κ³Ό:

  • 1번 μΆœκΈˆμ€ 이미 DB에 λ°˜μ˜λ˜μ–΄ 버렸고, 2λ²ˆμ—μ„œ μ—λŸ¬κ°€ λ‚˜μ„œ μ€‘λ‹¨λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  • 데이터 뢈일치(Inconsistency)κ°€ λ°œμƒν•©λ‹ˆλ‹€.

[2. νŠΈλžœμž­μ…˜μ΄ μžˆλŠ” 경우]

κ²°κ³Ό:

  • 2λ²ˆμ—μ„œ μ—λŸ¬(μ˜ˆμ™Έ)κ°€ λ°œμƒν•˜μž, μŠ€ν”„λ§μ΄ 이λ₯Ό κ°μ§€ν•˜κ³  μžλ™μœΌλ‘œ 둀백을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

  • 1번 좜금 내역도 μ·¨μ†Œλ˜μ–΄ 두 κ³„μ’Œ λͺ¨λ‘ 초기 μƒνƒœ(10,000원)λ₯Ό μœ μ§€ν•©λ‹ˆλ‹€. 데이터 일관성이 μ§€μΌœμ§„ κ²ƒμž…λ‹ˆλ‹€.

@Transactional μ‚¬μš© μ‹œ 주의점

@Transactional은 개발자λ₯Ό νŽΈν•˜κ²Œ ν•΄μ£Όμ§€λ§Œ, 그만큼 λ™μž‘ 원리λ₯Ό 잘 μ•Œμ•„μ•Ό μ‹€μˆ˜λ₯Ό 막을 수 μžˆμŠ΅λ‹ˆλ‹€.

1. λ™μž‘ 원리: AOP (Aspect Oriented Programming)

이 μ–΄λ…Έν…Œμ΄μ…˜μ„ 뢙이면 μŠ€ν”„λ§μ€ ν”„λ‘μ‹œ(Proxy)λΌλŠ” κ°€μ§œ 객체λ₯Ό λ§Œλ“€μ–΄ μ•žλ‹¨μ— μ„Έμ›λ‹ˆλ‹€.

  • ν”„λ‘μ‹œκ°€ νŠΈλžœμž­μ…˜μ„ μ‹œμž‘(BEGIN)ν•˜κ³ ,

  • μ‹€μ œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ λ’€,

  • μ„±κ³΅ν•˜λ©΄ COMMIT, μ˜ˆμ™Έκ°€ ν„°μ§€λ©΄ ROLLBACK을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

[μ£Όμ˜ν•  점: Self-Invocation]

  • 같은 클래슀 λ‚΄λΆ€μ˜ λ©”μ„œλ“œλΌλ¦¬ 호좜(this.method())ν•  λ•ŒλŠ” ν”„λ‘μ‹œλ₯Ό κ±°μΉ˜μ§€ μ•Šκ³  직접 ν˜ΈμΆœν•˜κΈ° λ•Œλ¬Έμ— νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

2. λ‘€λ°± κΈ°μ€€

기본적으둜 μŠ€ν”„λ§μ€ RuntimeException (Unchecked Exception)이 λ°œμƒν–ˆμ„ λ•Œλ§Œ λ‘€λ°±ν•©λ‹ˆλ‹€.

  • Checked Exception이 λ°œμƒν•΄λ„ λ‘€λ°±ν•˜κ³  μ‹Άλ‹€λ©΄?

    • rollbackFor = Exception.class μ˜΅μ…˜μ„ μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

3. νŠΈλžœμž­μ…”λ„ μ£Όμš” 속성

  • propagation (μ „νŒŒ 속성): 이미 μ§„ν–‰ 쀑인 νŠΈλžœμž­μ…˜μ΄ μžˆμ„ λ•Œ, ν•©λ₯˜ν• μ§€ μƒˆλ‘œ λ§Œλ“€μ§€ κ²°μ •ν•©λ‹ˆλ‹€. (λΆ€λͺ¨-μžμ‹ νŠΈλžœμž­μ…˜ μ œμ–΄)

  • isolation (격리 μˆ˜μ€€): μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ΄ λ™μ‹œμ— 싀행될 λ•Œ μ„œλ‘œ μ–Όλ§ˆλ‚˜ 영ν–₯을 주고받을지 μ„€μ •ν•©λ‹ˆλ‹€. (λ™μ‹œμ„± λ¬Έμ œμ™€ 직결됨)

  • readOnly (읽기 μ „μš©): true둜 μ„€μ •ν•˜λ©΄ 데이터 변경을 막고, μ„±λŠ₯ μ΅œμ ν™”(더티 체킹 μƒλž΅ λ“±)λ₯Ό λ•μŠ΅λ‹ˆλ‹€.

Last updated