Transactional

μŠ€ν”„λ§μ€ PlatformTransactionManager μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 νŠΈλžœμž­μ…˜μ„ μΆ”μƒν™”ν•˜κ³  선언적 νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜μ—¬ νŠΈλžœμž­μ…˜μ„ νŽΈλ¦¬ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ„λ‘ μ§€μ›ν•œλ‹€. @Transactional을 ν†΅ν•œ 선언적 νŠΈλžœμž­μ…˜ 관리 방식을 μ‚¬μš©ν•˜λ©΄ ν”„λ‘μ‹œ λ°©μ‹μ˜ AOPκ°€ μ μš©λ˜λŠ”λ° 그둜 인해 μ•„λž˜μ™€ 같은 νŠΉμ§•μ„ κ°€μ§€κ²Œ λœλ‹€.

  • @Transactional μ• λ…Έν…Œμ΄μ…˜μ΄ νŠΉμ • ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œμ— ν•˜λ‚˜λΌλ„ 있으면 νŠΈλžœμž­μ…˜ AOPλŠ” ν”„λ‘μ‹œλ₯Ό λ§Œλ“€μ–΄ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— 등둝

  • μ‹€μ œ 객체 λŒ€μ‹ μ— ν”„λ‘μ‹œλ₯Ό μŠ€ν”„λ§ λΉˆμ— λ“±λ‘ν•œ λ’€ ν”„λ‘μ‹œλŠ” μ‹€μ œ 객체λ₯Ό μ°Έμ‘°

  • λ§Œμ•½ λ‹€λ₯Έ κ³³μ—μ„œ ν•΄λ‹Ή 객체λ₯Ό μ˜μ‘΄κ΄€κ³„ μ£Όμž…μ„ μš”μ²­ν•˜κ²Œ 되면 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ μ‹€μ œ 객체 λŒ€μ‹ μ— λ“±λ‘λ˜μ–΄ 있던 ν”„λ‘μ‹œ 객체λ₯Ό μ£Όμž…

  • μ΅œμ’…μ μœΌλ‘œ λ‹€λ₯Έ 객체 -> μ‹€μ œ 객체 -> ν”„λ‘μ‹œ 객체 순으둜 μ˜μ‘΄κ΄€κ³„κ°€ μ£Όμž…λ˜κ²Œ 됨

** ν”„λ‘μ‹œλŠ” κΈ°μ‘΄ μ‹€μ œ 객체λ₯Ό μƒμ†ν•΄μ„œ λ§Œλ“€μ–΄μ§€κΈ° λ•Œλ¬Έμ— λ‹€ν˜•μ„±μ„ μ§€μ›ν•˜μ—¬ μ‹€μ œ 객체에 ν”„λ‘μ‹œ 객체가 μ£Όμž… 될 수 μžˆλ‹€.

νŠΈλžœμž­μ…˜ λ™μž‘ 방식

  1. ν”„λ‘μ‹œ 객체가 μš”μ²­μ„ λ¨Όμ € λ°›μŒ

  2. ν”„λ‘μ‹œ κ°μ²΄μ—μ„œ νŠΈλžœμž­μ…˜ μ‹œμž‘

  3. ν”„λ‘μ‹œ κ°μ²΄μ—μ„œ μ‹€μ œ 객체의 λ©”μ„œλ“œ 호좜

  4. μ‹€μ œ 객체 둜직 μˆ˜ν–‰

  5. ν”„λ‘μ‹œ κ°μ²΄μ—μ„œ νŠΈλžœμž­μ…˜ 컀밋 λ˜λŠ” λ‘€λ°±

νŠΈλžœμž­μ…˜ μš°μ„  μˆœμœ„

@Transactional μ• λ…Έν…Œμ΄μ…˜μ€ 클래슀, μΈν„°νŽ˜μ΄μŠ€, λ©”μ„œλ“œμ— μ μš©ν•  수 있으며, μš°μ„ μˆœμœ„λŠ” 더 ꡬ체적이고 μžμ„Έν•œ 것이 높은 μš°μ„ μˆœμœ„λ₯Ό κ°€μ§€λŠ” 것을 μ›μΉ™μœΌλ‘œ ν•œλ‹€. μΆ”κ°€μ μœΌλ‘œ μ ‘κ·Όμ œμ–΄μžκ°€ public인 κ²½μš°μ—λ§Œ νŠΈλžœμž­μ…˜μ΄ μ μš©λœλ‹€.(κ³Όλ„ν•˜κ²Œ μ μš©λ˜λŠ” 것을 λ°©μ§€)

  1. 클래슀의 λ©”μ„œλ“œ

  2. 클래슀

  3. μΈν„°νŽ˜μ΄μŠ€μ˜ λ©”μ„œλ“œ

  4. μΈν„°νŽ˜μ΄μŠ€

자기 호좜(Self Invocation)

@Transactional이 적용 됐을 λ•Œ νŠΈλžœμž­μ…˜μ΄ μ μš©μ€ ν”„λ‘μ‹œ 객체λ₯Ό 톡해 μˆ˜ν–‰λ˜λŠ”λ°, λ§Œμ•½ ν”„λ‘μ‹œ 객체λ₯Ό κ±°μΉ˜μ§€ μ•Šκ³  λŒ€μƒ 객체λ₯Ό 직접 ν˜ΈμΆœν•˜κ²Œ 되면 νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€. λ³΄ν†΅μ˜ κ²½μš°λŠ” ν”„λ‘μ‹œ 객체λ₯Ό 거치기 λ•Œλ¬Έμ— λ¬Έμ œκ°€ λ˜μ§€ μ•Šμ§€λ§Œ, λŒ€μƒ 객체 λ‚΄λΆ€μ—μ„œ λ©”μ„œλ“œ ν˜ΈμΆœμ„ ν•˜κ²Œ 되면 ν”„λ‘μ‹œλ₯Ό κ±°μΉ˜μ§€ μ•Šκ²Œ λ˜μ–΄ μœ„μ˜ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆλ‹€.

class Example {

    public void external() {
        // do something
        internal(); // ν”„λ‘μ‹œλ₯Ό κ±°μΉ˜μ§€ μ•Šκ³  λŒ€μƒ 객체 λ‚΄λΆ€μ—μ„œ λ©”μ„œλ“œ ν˜ΈμΆœν•˜κΈ° λ•Œλ¬Έμ— νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.
    }

    @Transactional
    public void internal() {
        // do something
    }
}

ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ external λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν–ˆμ„ λ•Œ λ‹€μŒκ³Ό 같은 ν”„λ‘œμ„ΈμŠ€κ°€ μ§„ν–‰λœλ‹€.

  1. ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ ν”„λ‘μ‹œ 호좜

  2. ν”„λ‘μ‹œμ—μ„œ external λ©”μ„œλ“œμ— νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ–΄ μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— νŠΈλžœμž­μ…˜ 없이 λ©”μ„œλ“œ 호좜

  3. μ‹€μ œ external λ©”μ„œλ“œ μ‹€ν–‰

  4. external λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ internal λ©”μ„œλ“œ 호좜

  5. μ‹€ν–‰ 된 internal λ©”μ„œλ“œλŠ” μ‹€μ œ κ°μ²΄μ—μ„œ μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμ— νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.

이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ ν•΄κ²°λ°©μ•ˆλ“€μ΄ μ‘΄μž¬ν•˜μ§€λ§Œ 보톡 μ‹€λ¬΄μ—μ„œλŠ” 별도 클래슀둜 λΆ„λ¦¬ν•˜μ—¬ ν˜ΈμΆœν•˜λŠ” 것이 κ°€μž₯ μ μ ˆν•œ 방법이닀.

μ΄ˆκΈ°ν™” μ‹œμ 

μŠ€ν”„λ§ μ΄ˆκΈ°ν™” μ‹œμ μ—λŠ” νŠΈλžœμž­μ…˜ AOPκ°€ μ μš©λ˜μ§€ μ•Šμ„ 수 있기 λ•Œλ¬Έμ— νŠΈλžœμž­μ…˜μ΄ ν•„μš”ν•œ 둜직이 ν•„μš”ν•œ λ©”μ„œλ“œ μ‹€ν–‰ μ‹œμ μ„ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μ™„μ „νžˆ μƒμ„±λ˜κ³  λ‚œ 뒀에 ν˜ΈμΆœν•  수 μžˆλ„λ‘ μ„€μ •ν•˜λŠ” 것이 μ’‹λ‹€.

class Hello {

    @PostConstruct
    @Transactional
    public void init1() {
        boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
        log.info("tx active={} ", isActive); // false
    }

    @EventListener(ApplicationReadyEvent.class)
    @Transactional
    public void init2() {
        boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
        log.info("tx active={} ", isActive); // true
    }
}

νŠΈλžœμž­μ…˜ μ˜΅μ…˜

@Transactional μ• λ…Έν…Œμ΄μ…˜μ„ 톡해 νŠΈλžœμž­μ…˜μ„ μ μš©ν•  λ•Œ μ•„λž˜μ™€ 같이 μ˜΅μ…˜μ„ μ„€μ •ν•  수 있으며, μ§€μ •ν•˜μ§€ μ•Šμ€ κ²½μš°μ—” 기본값이 μ μš©λœλ‹€.


@Transactional(isolation = Isolation.DEFAULT, readOnly = false)
class Example {

}

μ• λ…Έν…Œμ΄μ…˜μ— μ μš©ν•  수 μžˆλŠ” μ˜΅μ…˜λ“€μ€ μ•„λž˜μ™€ κ°™λ‹€.

1. rollbackFor / noRollbackFor

μ˜ˆμ™Έ λ°œμƒμ‹œ μŠ€ν”„λž‘ νŠΈλžœμž­μ…˜μ˜ λ‘€λ°± μ •μ±…μœΌλ‘œ κΈ°λ³Έ 정책은 μ•„λž˜μ™€ κ°™λ‹€.

  • 언체크 μ˜ˆμ™Έ: λ‘€λ°±

  • 체크 μ˜ˆμ™Έ: λ‘€λ°±ν•˜μ§€ μ•Šκ³  컀밋

이 μ˜΅μ…˜μ— μΆ”κ°€λ‘œ λ‘€λ°±ν•  μ˜ˆμ™Έλ₯Ό μ§€μ •ν•˜κ²Œ 되면, ν•΄λ‹Ή μ˜ˆμ™Έκ°€ λ°œμƒν–ˆμ„ λ•Œ λ‘€λ°±ν•˜κ²Œ λœλ‹€.


@Transactional(rollbackFor = Exception.class)
class Example {

}

λ°˜λŒ€λ‘œ noRollbackFor μ˜΅μ…˜μ€ λ‘€λ°±ν•˜μ§€ μ•Šμ„ μ˜ˆμ™Έλ₯Ό μ§€μ •ν•  수 μžˆλ‹€.

2. isolation

νŠΈλžœμž­μ…˜ 격리 μˆ˜μ€€ μ§€μ •μœΌλ‘œ 보톡 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ„€μ •ν•œ νŠΈλžœμž­μ…˜ μˆ˜μ€€μ„ μ‚¬μš©ν•˜λŠ” DEFAULTλ₯Ό μ‚¬μš©ν•œλ‹€. 격리 μˆ˜μ€€μ— λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ 격리 μˆ˜μ€€ μ°Έκ³ 

3. timeout

νŠΈλžœμž­μ…˜ νƒ€μž„μ•„μ›ƒμ„ μ§€μ •ν•˜λŠ” μ˜΅μ…˜μœΌλ‘œ 기본값은 -1둜 λ¬΄μ œν•œμ΄λ‹€.

4. readOnly

읽기 μ „μš© νŠΈλžœμž­μ…˜μœΌλ‘œ 기본값은 false으둜, 읽기 μ“°κΈ°κ°€ λͺ¨λ‘ κ°€λŠ₯ν•œ νŠΈλžœμž­μ…˜μ΄ μ μš©λœλ‹€. true μ˜΅μ…˜μ„ μ‚¬μš©ν•˜λ©΄ 읽기 μ „μš© νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ–΄ 읽기 μž‘μ—…λ§Œ κ°€λŠ₯ν•˜λ‹€.(λ“œλΌμ΄λ²„λ‚˜ DB에 따라 읽기 μ „μš© νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜μ§€ μ•Šμ„ 수 μžˆλ‹€.) 읽기 μ „μš©μ„ μ μš©ν•˜κ²Œ 되면 μ•„λž˜μ™€ 같은 차이점이 μžˆλ‹€.

  • ν”„λ ˆμž„μ›Œν¬: 읽기 μ „μš©μ΄κΈ° λ•Œλ¬Έμ— 변경에 μ‚¬μš©λ˜λŠ” ν”ŒλŸ¬μ‹œλ₯Ό ν˜ΈμΆœν•  ν•„μš”κ°€ μ—†μœΌλ©°, λ³€κ²½ 감지λ₯Ό μœ„ν•œ μŠ€λƒ…μƒ· 객체λ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ•„ λ‹€ν–₯ν•œ μ„±λŠ₯상 이점을 κ°€μ Έμ˜¬ 수 μžˆλ‹€.

  • JDBC λ“œλΌμ΄λ²„: λ³€κ²½ 쿼리가 λ°œμƒν•˜λ©΄ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚€κΈ° λ•Œλ¬Έμ— λ³€κ²½ 쿼리λ₯Ό μ‹€ν–‰ν•˜μ§€ μ•ŠλŠ”λ‹€.

  • λ°μ΄ν„°λ² μ΄μŠ€: 읽기 μ „μš© νŠΈλžœμž­μ…˜μ€ 읽기만 ν•˜λ©΄ λ˜μ–΄ λ‚΄λΆ€ μ„±λŠ₯ μ΅œμ ν™”κ°€ λ°œμƒν•œλ‹€.(λ―Έλ―Έν•œ 차이)

5. propagation

νŠΈλžœμž­μ…˜ μ „νŒŒ μ˜΅μ…˜μœΌλ‘œ 기본값은 REQUIRED둜, λŒ€λΆ€λΆ„ 이 μ˜΅μ…˜μ„ μ‚¬μš©ν•œλ‹€.

μ˜΅μ…˜
μ„€λͺ…
κΈ°μ‘΄ νŠΈλžœμž­μ…˜ X
κΈ°μ‘΄ νŠΈλžœμž­μ…˜ O

REQUIRED

ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜ μ‚¬μš©

μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜ 생성

κΈ°μ‘΄ νŠΈλžœμž­μ…˜ μ‚¬μš©

REQUIRES_NEW

항상 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜ μ‚¬μš©

μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜ 생성

μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜ 생성

SUPPORT

νŠΈλžœμž­μ…˜ 지원

νŠΈλžœμž­μ…˜ 없이 μ§„ν–‰

κΈ°μ‘΄ νŠΈλžœμž­μ…˜ μ‚¬μš©

NOT_SUPPORTED

νŠΈλžœμž­μ…˜ 미지원

νŠΈλžœμž­μ…˜ 없이 μ§„ν–‰

νŠΈλžœμž­μ…˜ 없이 μ§„ν–‰(κΈ°μ‘΄ νŠΈλžœμž­μ…˜ 보λ₯˜)

MANDATORY

νŠΈλžœμž­μ…˜μ΄ λ°˜λ“œμ‹œ μ‘΄μž¬ν•΄μ•Ό 함

μ˜ˆμ™Έ λ°œμƒ

κΈ°μ‘΄ νŠΈλžœμž­μ…˜ μ‚¬μš©

NEVER

νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•˜μ§€ μ•ŠμŒ

νŠΈλžœμž­μ…˜ 없이 μ§„ν–‰

μ˜ˆμ™Έ λ°œμƒ

isolation , timeout , readOnly λŠ” νŠΈλžœμž­μ…˜μ΄ 처음 μ‹œμž‘λ  λ•Œλ§Œ 적용되며, νŠΈλžœμž­μ…˜μ— μ°Έμ—¬ν•˜λŠ” κ²½μš°μ—λŠ” μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.

νŠΈλžœμž­μ…˜ μ „νŒŒ 흐름 - REQUIRED μ˜΅μ…˜

νŠΈλžœμž­μ…˜ μ „νŒŒ μ˜΅μ…˜μ΄ REQUIRED인 경우 이미 νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•˜λ©΄ ν•΄λ‹Ή νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•˜κ³  μ—†μœΌλ©΄ μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ„ μƒμ„±ν•˜κ²Œ λœλ‹€. ν•˜λ‚˜μ˜ 컀밋이라도 λ°œμƒν•˜λ©΄ 전체 νŠΈλžœμž­μ…˜μ΄ μ»€λ°‹λ˜κ³ , ν•˜λ‚˜μ˜ 둀백이라도 λ°œμƒν•˜λ©΄ 전체 νŠΈλžœμž­μ…˜μ΄ 둀백되며, κ·Έ 원리와 μˆœμ„œλŠ” μ•„λž˜μ™€ κ°™λ‹€.

νŠΈλžœμž­μ…˜ μš”μ²­/응닡 흐름
  • λ‚΄λΆ€ νŠΈλžœμž­μ…˜ μ‹€νŒ¨λ‘œ μ™ΈλΆ€ νŠΈλžœμž­μ…˜μ΄ λ‘€λ°±λ˜λŠ” μ˜ˆμ‹œ

// μ™ΈλΆ€ νŠΈλžœμž­μ…˜
@Service
public class BatchRegistrationService {

    private final MemberService memberService;

    public BatchRegistrationService(MemberService memberService) {
        this.memberService = memberService;
    }

    @Transactional
    public void registerMultipleMembers() {
        for (long point = 0; point < 5; point++) {
            try {
                memberService.registerMember(point);
            } catch (Exception e) {
                System.out.println("μ˜ˆμ™Έ λ°œμƒ: " + e.getMessage());
            }
        }
    }
}

// λ‚΄λΆ€ νŠΈλžœμž­μ…˜
@Service
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Transactional
    public void registerMember(long point) {
        if (point == 2L) {
            throw new RuntimeException("ν¬μΈνŠΈκ°€ 2인 νšŒμ›μ€ 등둝할 수 μ—†μŠ΅λ‹ˆλ‹€.");
        }
        Member member = new Member(point);
        memberRepository.save(member);
    }
}

μ™ΈλΆ€ νŠΈλžœμž­μ…˜μ—μ„œ μ˜ˆμ™Έλ₯Ό κ°μ‹Έμ„œ μ™ΈλΆ€ νŠΈλžœμž­μ…˜μ—μ„œμ˜ μ˜ˆμ™Έ λ°œμƒμ„ λ°©μ§€ν–ˆμ§€λ§Œ, λ‚΄λΆ€ νŠΈλžœμž­μ…˜μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ—¬ λ‘€λ°± λ§ˆν‚ΉλκΈ° λ•Œλ¬Έμ— 전체 νŠΈλžœμž­μ…˜μ΄ λ‘€λ°±λœλ‹€.

참고자료

Last updated

Was this helpful?