[Spring Boot] @Transactional의 7가지 μ „νŒŒ 속성, ν…ŒμŠ€νŠΈλ₯Ό ν†΅ν•œ λ‘€λ°± 검증

1. κ°œμš”

맀일 κ°œλ°œν•˜λ©° μ‚¬μš©ν•΄μ˜€λ˜ @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ— λŒ€ν•΄ μ•„λŠ”κ²Œ λ„ˆλ¬΄ μ—†λ‹€κ³  λŠκΌˆλ‹€. μ—¬λŸ¬ μ „νŒŒ μ „λž΅, μ˜΅μ…˜μ΄ μžˆλ‹€λŠ”κ±° μ •λ„λ§Œ μ•Œκ³ μžˆμ—ˆμ§€λ§Œ, 깊게 고렀해보진 μ•Šμ•˜λ˜ 것 κ°™λ‹€. 

 

 

이참에 κ³΅λΆ€ν•˜κ³  μ œλŒ€λ‘œ μ•Œκ³  μ‚¬μš©ν•˜κ³ μž 이 글을 μž‘μ„±ν•œλ‹€.

 

 

 

 

 

 

 

 

 

 

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

@Transactional 을 μ•Œμ•„λ³΄κΈ° μ•žμ„œ νŠΈλžœμž­μ…˜μ— λŒ€ν•΄ ν•œλ²ˆ 더 짚고 λ„˜μ–΄κ°€μž.

 

νŠΈλžœμž­μ…˜(Transaction)의 사전적 μ˜λ―ΈλŠ” 거래이고,

컴퓨터 κ³Όν•™ λΆ„μ•Όμ—μ„œμ˜ νŠΈλžœμž­μ…˜(Transaction)은 "더이상 뢄할이 λΆˆκ°€λŠ₯ν•œ μ—…λ¬΄μ²˜λ¦¬μ˜ λ‹¨μœ„"λ₯Ό μ˜λ―Έν•œλ‹€.

 

 

이것은 ν•˜λ‚˜μ˜ μž‘μ—…μ„ μœ„ν•΄ 더이상 뢄할될 수 μ—†λŠ” λͺ…λ Ήλ“€μ˜ λͺ¨μŒ, 즉, ν•œκΊΌλ²ˆμ— μˆ˜ν–‰λ˜μ–΄μ•Ό ν•  일련의 μ—°μ‚°λͺ¨μŒμ„ μ˜λ―Έν•œλ‹€. 

 

 

 

λ°μ΄ν„°λ² μ΄μŠ€μ™€ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 데이터 거래(Transaction)에 μžˆμ–΄μ„œ μ•ˆμ „μ„±μ„ ν™•λ³΄ν•˜κΈ° μœ„ν•œ 방법이 νŠΈλžœμž­μ…˜μΈ 것이닀.

 

 

 

νŠΈλžœμž­μ…˜μ˜ νŠΉμ§•μ€ 크게 4κ°€μ§€λ‘œ λ‚˜λ‰œλ‹€.

  • μ›μžμ„± (Atomicity)
  • 일관성 (Consistency)
  • 독립성 (Isolation)
  • 지속성 (Durability)

 

μ›μžμ„±

1. νŠΈλžœμž­μ…˜μ˜ 연산은 λ°μ΄ν„°λ² μ΄μŠ€μ— λͺ¨λ‘ λ°˜μ˜λ˜λ˜μ§€ μ•„λ‹ˆλ©΄ λͺ¨λ‘ λ°˜μ˜λ˜μ§€ μ•Šμ•„μ•Όν•œλ‹€.

2. νŠΈλžœμž­μ…˜ λ‚΄μ˜ λͺ¨λ“  λͺ…령은 λ°˜λ“œμ‹œ μ™„λ²½νžˆ μˆ˜ν–‰λ˜μ–΄μ•Ό ν•˜λ©°, ν•˜λ‚˜λΌλ„ 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ νŠΈλžœμž­μ…˜ μ „λΆ€κ°€ μ·¨μ†Œλ˜μ–΄μ•Ό ν•œλ‹€.

 

일관성

1. νŠΈλžœμž­μ…˜μ„ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œν•˜λ©΄ 일관성 μžˆλŠ” λ°μ΄ν„°λ² μ΄μŠ€ μƒνƒœλ‘œ λ³€ν™˜ν•œλ‹€.

2. μ‹œμŠ€ν…œμ΄ 가지고 μžˆλŠ” κ³ μ •μš”μ†ŒλŠ” νŠΈλžœμž­μ…˜ μˆ˜ν–‰ μ „κ³Ό νŠΈλžœμž­μ…˜ μˆ˜ν–‰ μ™„λ£Œ ν›„μ˜ μƒνƒœκ°€ κ°™μ•„μ•Ό ν•œλ‹€.

 

독립성

1. λ‘˜ μ΄μƒμ˜ νŠΈλžœμž­μ…˜μ΄ λ™μ‹œμ— μ‹€ν–‰λ˜λŠ” 경우 λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ˜ 연산이 끼어듀 수 μ—†λ‹€.

2. μˆ˜ν–‰μ€‘인 νŠΈλžœμž­μ…˜μ€ μ™„μ „νžˆ μ™„λ£Œλ  λ•ŒκΉŒμ§€ λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ—μ„œ μˆ˜ν–‰ κ²°κ³Όλ₯Ό μ°Έμ‘°ν•  수 μ—†λ‹€.

 

지속성

1. μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλœ νŠΈλžœμž­μ…˜μ˜ κ²°κ³ΌλŠ” 영ꡬ적으둜 λ°˜μ˜λ˜μ–΄μ•Ό ν•œλ‹€.

 

 

 

 

 

 

 

 

 

 

 

 

3. μŠ€ν”„λ§μ—μ„œμ˜ Transaction

μŠ€ν”„λ§μ—μ„œλŠ” νŠΈλžœμž­μ…˜(Transaction)을 κ΄€λ¦¬ν•˜κΈ° μœ„ν•΄ @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ œκ³΅ν•œλ‹€. 

 

μŠ€ν”„λ§μ˜ νŠΈλžœμž­μ…˜μ€ ν”„λ‘œκ·Έλž˜λ° 방식과 선언적 방식 두 κ°€μ§€λ‘œ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, λŒ€λΆ€λΆ„μ˜ 경우 선언적 방식을 μ„ ν˜Έν•˜κ³  @Transactional 이 이에 ν•΄λ‹Ήλœλ‹€. 

 

클래슀 λ˜λŠ” λ©”μ„œλ“œ μœ„μ— @Transactional을 뢙이면, νŠΈλžœμž­μ…˜ κΈ°λŠ₯이 적용된 ν”„λ‘μ‹œ 객체가 μƒμ„±λ˜λ©°, νŠΈλžœμž­μ…˜ 성곡 여뢀에 따라 Commit λ˜λŠ” Rollback μž‘μ—…μ΄ 이루어진닀.

 

 

 

 

μŠ€ν”„λ§μ—μ„œ νŠΈλžœμž­μ…˜μ„ κ΄€λ¦¬ν•˜λŠ” 방법

Spring이 μ œκ³΅ν•˜λŠ” @Transactional μ˜ μž₯점 쀑 ν•˜λ‚˜λŠ” μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ„ λ¬Άμ–΄μ„œ μ»€λ‹€λž€ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜ 경계λ₯Ό λ§Œλ“€ 수 μžˆλ‹€λŠ” 점이닀.

 

 

κ°œλ°œμ„ ν•˜λ‹€ 보면 νŠΈλžœμž­μ…˜ 쀑에 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ„ λ§Œλ“€μ–΄μ•Ό ν•  λ•Œλ„ μžˆλŠ”λ°, μ΄λ•Œ μ–΄λ–»κ²Œ νŠΈλžœμž­μ…˜μ„ μ²˜λ¦¬ν•  것인지에 λŒ€ν•΄ μŠ€ν”„λ§μ€ μ—¬λŸ¬ 속성을 μ œκ³΅ν•΄μ€€λ‹€. 이것이 μ „νŒŒ 속성(Propagation)이닀.

 

μ „νŒŒ 속성에 따라 기쑴의 νŠΈλžœμž­μ…˜μ— μ°Έμ—¬ν•  μˆ˜λ„ 있고, λ³„λ„μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ 진행할 μˆ˜λ„ 있고, μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λŠ” λ“± μ—¬λŸ¬ 선택을 ν•  수 μžˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μ΄ λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ„ λ§Œλ‚˜λŠ” 상황을 그림으둜 λ‚˜νƒ€λ‚΄λ©΄ λ‹€μŒκ³Ό κ°™λ‹€. 

 

 

이런 상황을 μœ„ν•΄ 이λ₯Ό 물리 νŠΈλžœμž­μ…˜κ³Ό 논리 νŠΈλžœμž­μ…˜μœΌλ‘œ λ‚˜λˆ„μ–΄ μ²˜λ¦¬ν•œλ‹€. 

 

물리 νŠΈλžœμž­μ…˜μ€ μ‹€μ œ λ°μ΄ν„°λ² μ΄μŠ€μ— μ μš©λ˜λŠ” νŠΈλžœμž­μ…˜μœΌλ‘œ, 컀λ„₯μ…˜μ„ 톡해 컀밋/λ‘€λ°±ν•˜λŠ” λ‹¨μœ„μ΄κ³ ,

논리 νŠΈλžœμž­μ…˜μ€ μŠ€ν”„λ§μ΄ μ²˜λ¦¬ν•˜λŠ” νŠΈλžœμž­μ…˜ μ˜μ—­μ„ κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄ λ§Œλ“€μ–΄μ§„ κ°œλ…μ΄λ‹€.

 

 

예λ₯Ό λ“€μ–΄ λ‹€μŒμ˜ 그림은 μ™ΈλΆ€ νŠΈλžœμž­μ…˜κ³Ό λ‚΄λΆ€ νŠΈλžœμž­μ…˜μ΄ 1개의 물리 νŠΈλžœμž­μ…˜(컀λ„₯μ…˜)을 μ‚¬μš©ν•˜λŠ” κ²½μš°μ΄λ‹€.

 

 

기쑴의 νŠΈλžœμž­μ…˜μ΄ 진행쀑일 λ•Œ 또 λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ΄ μ‚¬μš©λ˜λ©΄ λ³΅μž‘ν•œ 상황이 λ°œμƒν•œλ‹€. μŠ€ν”„λ§μ€ 논리 νŠΈλžœμž­μ…˜μ΄λΌλŠ” κ°œλ…μ„ λ„μž…ν•¨μœΌλ‘œμ¨ 상황에 λŒ€ν•œ μ„€λͺ…을 μ‰½κ²Œ λ§Œλ“€κ³ , λ‹€μŒκ³Ό 같은 λ‹¨μˆœν•œ 원칙을 μ„ΈμšΈμˆ˜ μžˆμ—ˆλ‹€. 

 

 

1. λͺ¨λ“  논리 νŠΈλžœμž­μ…˜μ΄ μ»€λ°‹λ˜μ–΄μ•Ό 물리 νŠΈλžœμž­μ…˜μ΄ 컀밋됨 

2. ν•˜λ‚˜μ˜ 논리 νŠΈλžœμž­μ…˜μ΄λΌλ„ 둀백되면 물리 νŠΈλžœμž­μ…˜μ€ 둀백됨

 

 

 

 

νŠΈλžœμž­μ…˜ μ „νŒŒ 속성

 

μŠ€ν”„λ§μ˜ μ „νŒŒ μ†μ„±μ—λŠ” 총 7가지가 μžˆλ‹€.

 

 

 

1. REQUIRED

Defualt 속성이며, λͺ¨λ“  νŠΈλžœμž­μ…˜ λ§€λ‹ˆμ €κ°€ μ§€μ›ν•œλ‹€. 보톡 이 μ†μ„±μœΌλ‘œ 많이 μ‚¬μš©ν•œλ‹€. 미리 μ‹œμž‘λœ νŠΈλžœμž­μ…˜μ΄ 있으면 μ°Έμ—¬ν•˜κ³ , μ—†μœΌλ©΄ νŠΈλžœμž­μ…˜μ„ μƒμ„±ν•œλ‹€. 

 

λΆ€λͺ¨ λ©”μ„œλ“œμ™€ μžμ‹ λ©”μ„œλ“œκ°€ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬Άμ—¬ λ™μž‘ν•œλ‹€. ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬Άμ΄κΈ° λ•Œλ¬Έμ— λΆ€λͺ¨λ‚˜ μžμ‹μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ μ „체 νŠΈλžœμž­μ…˜μ΄ λ‘€λ°±λœλ‹€.

 

 

 

2. SUPPORTS

이미 μ‹œμž‘λœ νŠΈλžœμž­μ…˜μ΄ 있으면 μ°Έμ—¬ν•˜κ³  μ—†μœΌλ©΄ νŠΈλžœμž­μ…˜ 없이 μ§„ν–‰ν•œλ‹€. νŠΈλžœμž­μ…˜μ΄ μ—†κΈ΄ ν•˜μ§€λ§Œ ν•΄λ‹Ή 경계 μ•ˆμ—μ„œ Connectionμ΄λ‚˜ Hibernate Session 등을 κ³΅μœ ν•  수 μžˆλ‹€.

 

 

 

3. MANDATORY

REQUIRED와 λΉ„μŠ·ν•˜λ©°, 이미 μ‹œμž‘λœ νŠΈλžœμž­μ…˜μ΄ 있으면 μ°Έμ—¬ν•œλ‹€. ν•˜μ§€λ§Œ νŠΈλžœμž­μ…˜μ΄ μ—†λ‹€λ©΄ μƒμ„±ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚¨λ‹€. ν˜Όμžμ„œ λ…λ¦½μ μœΌλ‘œ νŠΈλžœμž­μ…˜μ„ μ‹€ν–‰ν•˜λ©΄ μ•ˆλ˜λŠ” κ²½μš°μ— μ‚¬μš©ν•œλ‹€.

 

 

 

4. REQUIRED_NEW

항상 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•œλ‹€. 이미 진행 쀑인 νŠΈλžœμž­μ…˜μ΄ μžˆλ‹€λ©΄, νŠΈλžœμž­μ…˜μ„ 보λ₯˜μ‹œν‚¨λ‹€.

 

λΆ€λͺ¨ νŠΈλžœμž­μ…˜κ³Ό μžμ‹ λ©”μ„œλ“œμ˜ νŠΈλžœμž­μ…˜μ΄ μ™„μ „νžˆ λΆ„λ¦¬λ˜μ–΄ λ™μž‘ν•œλ‹€. μžμ‹ λ©”μ„œλ“œμ˜ νŠΈλžœμž­μ…˜μ΄ μ™„λ£Œλ˜λ©΄ λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ λ‹€μ‹œ ν™œμ„±ν™”λœλ‹€. λΆ€λͺ¨μ™€ μžμ‹ νŠΈλžœμž­μ…˜μ΄ μ„œλ‘œ λ…립적이기 λ•Œλ¬Έμ— ν•˜λ‚˜κ°€ μ‹€νŒ¨ν•˜λ”라도 λ‹€λ₯Έ ν•˜λ‚˜λŠ” μ˜ν–₯을 λ°›μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

 

 

 

5. NOT_SUPPORTED

νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•˜μ§€ μ•Šκ²Œ ν•œλ‹€. 이미 진행 쀑인 νŠΈλžœμž­μ…˜μ΄ 있으면 보λ₯˜μ‹œν‚¨λ‹€.

 

 

 

6. NEVER

νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•˜μ§€ μ•Šλ„λ‘ κ°•μ œν•œλ‹€. 이미 진행 쀑인 νŠΈλžœμž­μ…˜λ„ μ‘΄μž¬ν•˜λ©΄ μ•ˆλ˜λ©°, νŠΈλžœμž­μ…˜μ΄ μžˆλ‹€λ©΄ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

 

 

 

7. NESTED

이미 진행 쀑인 νŠΈλžœμž­μ…˜μ΄ 있으면 쀑첩 νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•œλ‹€. 쀑첩 νŠΈλžœμž­μ…˜μ€ λ§κ·ΈλŒ€λ‘œ νŠΈλžœμž­μ…˜ μ•ˆμ— νŠΈλžœμž­μ…˜μ„ λ§Œλ“œλŠ” 것이닀.독립적인 νŠΈλžœμž­μ…˜μ„ λ§Œλ“œλŠ” REQUIRED_NEWμ™€λŠ” λ‹€λ₯΄λ‹€.

 

μ€‘μ²©λœ νŠΈλžœμž­μ…˜μ€ λ¨Όμ € μ‹œμž‘λœ λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ˜ 컀밋과 λ‘€λ°±μ—λŠ” 영ν–₯을 λ°›μ§€λ§Œ, μžμ‹ μ˜ 컀밋과 둀백은 λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ—κ²Œ 영ν–₯을 주지 μ•ŠλŠ”λ‹€. μ΄λŸ° μ μ—μ„œ REQUIRED와도 λ‹€λ₯΄λ‹€

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4. ν…ŒμŠ€νŠΈ μ½”λ“œλ‘œ 검증

λͺ¨λ“  μ „νŒŒ 속성을 κ²€μ¦ν•˜μ§„ μ•Šμ•˜κ³ , λͺ‡ 가지 κΆκΈˆν•œ 속성듀에 λŒ€ν•΄μ„œλ§Œ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•˜μ˜€λ‹€.

 

 

1. REQUIERD - μžμ‹μ—μ„œ μ˜ˆμ™Έκ°€ ν„°μ§ˆ λ•Œ

// AService
@Transactional
public void saveWithRequiredFail(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    // μ˜ˆμ™Έ λ°œμƒ
    try {
        bService.saveMemberFail(bMember);
    } catch (RuntimeException e) {
        System.out.println("Required νŠΈλžœμž­μ…˜ λ‘€λ°± 처리: " + e.getMessage());
    }
}


// BService
@Transactional
public void saveMemberFail(Member bMember) {
    memberRepository.save(bMember);
    throw new RuntimeException();
}


// Test Code
@Test
@DisplayName("[REQUIRED] μžμ‹μ—μ„œ μ˜ˆμ™Έκ°€ ν„°μ‘Œμ„ λ•Œ")
public void saveWithRequiredFailTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    assertThatThrownBy(() -> aService.saveWithRequiredFail(aMember, bMember))
        .isInstanceOf(RuntimeException.class);

    assertThat(memberRepository.findAll()).isEmpty();
}

 

μžμ‹ λ©”μ„œλ“œμ—μ„œ λ°œμƒν•˜λŠ” μ˜ˆμ™Έλ₯Ό try - catch둜 μž‘μ•˜μ§€λ§Œ, μžμ‹ νŠΈλžœμž­μ…˜μ—μ„œ μ˜ˆμ™Έκ°€ ν„°μ§€λ©΄μ„œ λΆ€λͺ¨κΉŒμ§€ ν•¨κ»˜ λ‘€λ°±λœλ‹€. 

 

 

 

 

 

 

2.1 MANDATORY - νŠΈλžœμž­μ…˜ 없이 μžμ‹ νŠΈλžœμž­μ…˜μ„ ν˜ΈμΆœν–ˆμ„ λ•Œ

// AService
public void saveWithMandatoryFail(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    bService.saveMemberWithMandatory(bMember);
}


// BService
@Transactional(propagation = Propagation.MANDATORY)
public void saveMemberWithMandatory(Member bMember) {
    memberRepository.save(bMember);
}


// Test Code
@Test
@DisplayName("[MANDATORY] λΆ€λͺ¨κ°€ νŠΈλžœμž­μ…˜μ΄ 없을 λ•Œ")
public void saveWithMandatoryFailTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    // λΆ€λͺ¨μ—μ„œ νŠΈλžœμž­μ…˜ 없이 μ‹€ν–‰
    assertThatThrownBy(() -> aService.saveWithMandatoryFail(aMember, bMember))
        .isInstanceOf(IllegalTransactionStateException.class);
}

 

νŠΈλžœμž­μ…˜ 없이 MANDATORY 속성을 가진 ν•˜μœ„ νŠΈλžœμž­μ…˜μ„ ν˜ΈμΆœν•˜λ©΄ IllegalTransactionStateException μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€.

 

 

 

2.2 MANDATORY - νŠΈλžœμž­μ…˜ 있이 μžμ‹ νŠΈλžœμž­μ…˜μ„ ν˜ΈμΆœν–ˆμ„ λ•Œ

// AService
@Transactional
public void saveWithMandatorySuccess(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    bService.saveMemberWithMandatory(bMember);
}


// BService
@Transactional(propagation = Propagation.MANDATORY)
public void saveMemberWithMandatory(Member bMember) {
    memberRepository.save(bMember);
}


// Test Code
@Test
@DisplayName("[MANDATORY] μ €μž₯ 성곡 ν…ŒμŠ€νŠΈ")
public void saveWithMandatorySuccessTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    aService.saveWithMandatorySuccess(aMember, bMember);

    assertThat(memberRepository.findAll()).size().isEqualTo(2);
}

 

νŠΈλžœμž­μ…˜μ„ 달고 ν˜ΈμΆœν•˜λ©΄ μ˜ˆμ™Έ 없이 잘 μ €μž₯λœλ‹€.

 

 

 

 

 

3. NOT SUPPORTED - λΆ€λͺ¨μ—μ„œ μ˜ˆμ™Έκ°€ ν„°μ§ˆ λ•Œ NOT SUPPORTED 속성을 가진 μžμ‹μ΄ μžˆμ„ λ•Œ

// AService
@Transactional
public void saveWithNotSupported(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    bService.saveWithNotSupported(bMember);
    throw new RuntimeException();
}


// BService
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void saveWithNotSupported(Member bMember) {
    memberRepository.save(bMember);
}


// Test Code
@Test
@DisplayName("[NOT SUPPORTED] μžμ‹μ€ Not Supported 이고, λΆ€λͺ¨μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•  λ•Œ")
public void saveWithNotSupportedTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    assertThatThrownBy(() -> aService.saveWithNotSupported(aMember, bMember))
        .isInstanceOf(RuntimeException.class);

    assertThat(memberRepository.findAll()).size().isEqualTo(1);
}

 

NOT SUPPORTED 속성은 λΆ€λͺ¨μ˜ νŠΈλžœμž­μ…˜μ„ 보λ₯˜μ‹œν‚¨λ‹€κ³  λ˜μ–΄μžˆλ‹€. νŠΈλžœμž­μ…˜μ΄ Suspend된 μƒνƒœμ΄λ―€λ‘œ μžμ‹μ€ νŠΈλžœμž­μ…˜μ˜ 영ν–₯을 받지 μ•Šκ²Œ 되고, BServiceμ—μ„œ μ €μž₯ν•œ BMemberλŠ” μ¦‰μ‹œ Database에 μ €μž₯λœλ‹€. 

 

λ§Œμ•½ λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ—μ„œ μ˜ˆμ™Έκ°€ 터지지 μ•Šμ•˜λ”λΌλ©΄ bMember κ°€ Database에 μ €μž₯된 ν›„ aMemberκ°€ μ €μž₯됐을 것이닀. 

 

 

 

 

 

 

 

4. NEVER - λΆ€λͺ¨κ°€ νŠΈλžœμž­μ…˜μ΄ μžˆλŠ”λ°, μžμ‹μ΄ NEVER 속성을 κ°€μ§ˆ λ•Œ

// AService
@Transactional
public void saveWithNeverFail(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    bService.saveWithNeverFail(bMember);
}


// BService
@Transactional(propagation = Propagation.NEVER)
public void saveWithNeverFail(Member bMember) {
    memberRepository.save(bMember);
}


// Test Code
@Test
@DisplayName("[NEVER] μžμ‹μ€ Never 이고, λΆ€λͺ¨κ°€ νŠΈλžœμž­μ…˜μ΄ μžˆμ„ λ•Œ")
public void saveWithNeverFailTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    assertThatThrownBy(() -> aService.saveWithNeverFail(aMember, bMember))
        .isInstanceOf(IllegalTransactionStateException.class);
}

 

 

 

 

 

 

5.1 NESTED - λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ˜ 둀백이 NESTED 속성을 가진 μžμ‹μ—κ²Œ μ „νŒŒλ  λ•Œ

// AService
@Transactional
public void saveWithNestedParentException(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    bService.saveWithNestedParentException(bMember);
    throw new RuntimeException();
}


// BService
@Transactional(propagation = Propagation.NESTED)
public void saveWithNestedParentException(Member bMember) {
    memberRepository.save(bMember);
}


// Test Code
@Test
@DisplayName("[NESTED] λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ˜ 둀백이 μžμ‹μ—κ²Œ μ „νŒŒ")
public void saveWithNestedParentExceptionTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    assertThatThrownBy(() -> aService.saveWithNestedParentException(aMember, bMember))
        .isInstanceOf(RuntimeException.class);

    assertThat(memberRepository.findAll()).size().isEqualTo(0);
}

 

μžμ‹ νŠΈλžœμž­μ…˜μ΄ NESTED 속성을 κ°€μ§ˆ λ•Œ λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ—μ„œ μ˜ˆμ™Έκ°€ 터지면 μžμ‹ νŠΈλžœμž­μ…˜λ„ ν•¨κ»˜ λ‘€λ°±λœλ‹€. 

 

λ°˜λŒ€μ˜ 상황은 μ–΄λ–¨κΉŒ??

 

 

 

5.2 NESTED - NESTED 속성을 가진 μžμ‹ νŠΈλžœμž­μ…˜μ΄ 둀백될 λ•Œ

// AService
@Transactional
public void saveWithNestedChildException(Member aMember, Member bMember) {
    memberRepository.save(aMember);
    try {
        bService.saveWithNestedChildException(bMember); // 쀑첩 νŠΈλžœμž­μ…˜
    } catch (RuntimeException e) {
        System.out.println("쀑첩 νŠΈλžœμž­μ…˜ λ‘€λ°± 처리: " + e.getMessage());
    }
}


// BService
@Transactional(propagation = Propagation.NESTED)
public void saveWithNestedChildException(Member bMember) {
    memberRepository.save(bMember);
    throw new RuntimeException();
}


// Test Code
@Test
@DisplayName("[NESTED] μžμ‹ νŠΈλžœμž­μ…˜μ˜ 둀백이 λΆ€λͺ¨μ—κ²Œ μ „νŒŒλ˜μ§€ μ•ŠμŒ")
public void saveWithNestedChildExceptionTest() {
    Member aMember = new Member(1L);
    Member bMember = new Member(2L);

    aService.saveWithNestedChildException(aMember, bMember);

    assertThat(memberRepository.findAll()).size().isEqualTo(1);
}

 

μžμ‹μ˜ νŠΈλžœμž­μ…˜κ³ΌλŠ” λ¬΄κ΄€ν•˜κ²Œ λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ—μ„œ μ €μž₯ν•œ aMemberλŠ” μ»€λ°‹λœλ‹€.