νŠΈλžœμž­μ…˜ κ΄€λ¦¬λŠ” λ°μ΄ν„°λ² μ΄μŠ€μ˜ 일관성을 μœ μ§€ν•˜κΈ° μœ„ν•΄ ν•„μˆ˜μ μΈ κ³Όμ •μž…λ‹ˆλ‹€. 특히, Spring Framework와 같은 ν˜„λŒ€μ μΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 개발 ν™˜κ²½μ—μ„œλŠ” νŠΈλžœμž­μ…˜μ„ 효율적으둜 관리할 수 μžˆλŠ” λ‹€μ–‘ν•œ 도ꡬ와 μ–΄λ…Έν…Œμ΄μ…˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. 이번 κΈ€μ—μ„œλŠ” νŠΈλžœμž­μ…˜μ˜ κΈ°λ³Έ κ°œλ…κ³Ό Springμ—μ„œ @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ 일반적인 예제λ₯Ό λ‹€λ£Ήλ‹ˆλ‹€.

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

νŠΈλžœμž­μ…˜μ€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ μƒνƒœλ₯Ό λ³€ν™”μ‹œν‚€λŠ” ν•˜λ‚˜ μ΄μƒμ˜ 연산을 ν•˜λ‚˜μ˜ μž‘μ—… λ‹¨μœ„λ‘œ λ¬ΆλŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. μ΄λŠ” λͺ¨λ“  연산이 μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλ˜κ±°λ‚˜, ν•˜λ‚˜λΌλ„ μ‹€νŒ¨ν•  경우 λͺ¨λ“  변경사항이 μ·¨μ†Œλ˜μ–΄μ•Ό 함을 보μž₯ν•©λ‹ˆλ‹€(All or Nothing). 이λ₯Ό 톡해 λ°μ΄ν„°μ˜ 일관성과 정확성을 μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Spring의 @Transactional

Spring Frameworkμ—μ„œλŠ” @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜μ—¬ 선언적 νŠΈλžœμž­μ…˜ 관리λ₯Ό ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 μ–΄λ…Έν…Œμ΄μ…˜μ„ λ©”μ†Œλ“œλ‚˜ ν΄λž˜μŠ€μ— μ μš©ν•˜λ©΄, Spring은 ν•΄λ‹Ή λ©”μ†Œλ“œμ˜ 싀행을 νŠΈλžœμž­μ…˜μ˜ λ²”μœ„ μ•ˆμ—μ„œ κ΄€λ¦¬ν•©λ‹ˆλ‹€. 즉, λ©”μ†Œλ“œ μ‹€ν–‰ 전에 νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•˜κ³ , μ‹€ν–‰ ν›„μ—λŠ” 성곡 여뢀에 따라 νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜κ±°λ‚˜ λ‘€λ°±ν•©λ‹ˆλ‹€.

JPA와 @Transactional

Java Persistence API(JPA)λŠ” μžλ°” ORM κΈ°μˆ μ— λŒ€ν•œ API ν‘œμ€€μž…λ‹ˆλ‹€. JPAλ₯Ό μ‚¬μš©ν•  λ•Œ, 기본적으둜 λͺ¨λ“  λ°μ΄ν„°λ² μ΄μŠ€ 연산은 νŠΈλžœμž­μ…˜ μ•ˆμ—μ„œ 이루어져야 ν•©λ‹ˆλ‹€. λ§Žμ€ JPA κ΅¬ν˜„μ²΄(예: Hibernate)λŠ” λ‚΄λΆ€μ μœΌλ‘œ λ©”μ†Œλ“œμ— @Transactional이 μ μš©λ˜μ–΄ μžˆμ–΄, 단일 연산에 λŒ€ν•΄μ„œλŠ” λ³„λ„λ‘œ μ„ μ–Έν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ—¬λŸ¬ 연산을 ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬Άμ–΄ 관리해야 ν•  λ•ŒλŠ” κ°œλ°œμžκ°€ λͺ…μ‹œμ μœΌλ‘œ @Transactional을 μ„ μ–Έν•΄μ•Ό ν•©λ‹ˆλ‹€.

μ‚¬μš© μ˜ˆμ‹œ

λ‹€μŒμ€ @Transactional의 μ‚¬μš© μ˜ˆμ‹œμž…λ‹ˆλ‹€. test() λ©”μ†Œλ“œμ—μ„œλŠ” 두 개의 λ°μ΄ν„°λ² μ΄μŠ€ μ €μž₯ μž‘μ—…μ„ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬ΆμŠ΅λ‹ˆλ‹€. saveSuccess()λŠ” μ •μƒμ μœΌλ‘œ 데이터λ₯Ό μ €μž₯ν•˜μ§€λ§Œ, saveFail()μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ—¬ 두 μ—°μ‚° λͺ¨λ‘ λ‘€λ°±λ©λ‹ˆλ‹€. μ΄λŠ” @Transactional이 μ„ μ–Έλ˜μ–΄ 있기 λ•Œλ¬Έμ— κ°€λŠ₯ν•œ λ™μž‘μž…λ‹ˆλ‹€.

@Transactional
public void test() {
    saveSuccess();
    saveFail(); // 이 λ©”μ†Œλ“œμ—μ„œ μ˜ˆμ™Έ λ°œμƒ
}

public void saveSuccess() {
    // λ°μ΄ν„°λ² μ΄μŠ€μ— 데이터 μ €μž₯
}

public void saveFail() {
    // λ°μ΄ν„°λ² μ΄μŠ€μ— 데이터 μ €μž₯ μ‹œλ„, μ˜ˆμ™Έ λ°œμƒ
    throw new RuntimeException("μ €μž₯ μ‹€νŒ¨");
}

λ§Œμ•½ @Transactional을 μ„ μ–Έν•˜μ§€ μ•Šμ•˜λ‹€λ©΄, saveFail()의 μ‹€νŒ¨μ™€ λ¬΄κ΄€ν•˜κ²Œ saveSuccess()λŠ” λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯λ©λ‹ˆλ‹€. μ΄λŠ” νŠΈλžœμž­μ…˜μ΄ κ°œλ³„ μž‘μ—…μœΌλ‘œ κ΄€λ¦¬λ˜κΈ° λ•Œλ¬Έμ— λ°œμƒν•˜λŠ” ν˜„μƒμž…λ‹ˆλ‹€.

κ²°λ‘ 

@Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄, μ—¬λŸ¬ λ°μ΄ν„°λ² μ΄μŠ€ 연산을 ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬Άμ–΄ 일관성을 μœ μ§€ν•˜κ³ , μ˜ˆμ™Έ λ°œμƒ μ‹œ λͺ¨λ“  변경사항을 λ‘€λ°±ν•˜μ—¬ λ°μ΄ν„°μ˜ μ•ˆμ •μ„±μ„ 보μž₯

ν•  수 μžˆμŠ΅λ‹ˆλ‹€. Springκ³Ό JPAλ₯Ό μ‚¬μš©ν•˜λŠ” ν˜„λŒ€μ μΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κ°œλ°œμ—μ„œ νŠΈλžœμž­μ…˜ κ΄€λ¦¬λŠ” 맀우 μ€‘μš”ν•˜λ©°, @Transactional은 이λ₯Ό μ†μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.