λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

spring

[Spring] @Transactional λ‚΄λΆ€ν˜ΈμΆœ

πŸš€  κ°œμš”

ν”„λ‘œμ νŠΈμ—μ„œ νŠΈλžœμž­μ…˜μ„ 물리적으둜 뢄리해야 ν–ˆκ³ , 이 κ³Όμ •μ—μ„œ λ‚΄λΆ€ν˜ΈμΆœμ΄λΌλŠ” κ°œλ…μ„ μ•Œκ²Œ λ˜μ—ˆλ‹€. νŠΈλžœμž­μ…˜ λ‚΄λΆ€ ν˜ΈμΆœμ΄λž€ 무엇이고 μ™œ λ°œμƒν•˜λŠ” 것이며 μ–΄λ–»κ²Œ ν•΄κ²°ν•  수 μžˆλŠ”μ§€ μ•Œμ•„λ³΄μž.

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

νŠΈλžœμž­μ…˜μ΄λž€ 더 이상 μͺΌκ°€ 수 μ—†λŠ” μž‘μ—…μ˜ λ‹¨μœ„μ΄λ‹€. μ—¬κΈ°μ„œ μž‘μ—…μ€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ μƒνƒœλ₯Ό λ³€κ²½ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€. νŠΈλžœμž­μ…˜μ˜ νŠΉμ§•μ€ λ‹€μŒκ³Ό κ°™λ‹€.

  • μ›μžμ„±(Atomicity): νŠΈλžœμž­μ…˜ λ‚΄μ˜ μž‘μ—…μ€ λͺ¨λ‘ 성곡(Commit)ν•˜κ±°λ‚˜ λͺ¨λ‘ μ‹€νŒ¨(Rollback)λ˜μ–΄μ•Ό ν•œλ‹€.
  • 일관성(Consistency): νŠΈλžœμž­μ…˜μ€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ μƒνƒœλ₯Ό 일관성 있게 μœ μ§€ν•΄μ•Ό ν•œλ‹€. ex) μ œμ•½ 쑰건
  • 격리성(Isolation): μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ€ μ„œλ‘œ 영ν–₯을 λ―ΈμΉ˜μ§€ μ•Šκ³  λ…λ¦½μ μœΌλ‘œ μˆ˜ν–‰λ˜μ–΄μ•Ό ν•œλ‹€.
  • 지속성(Durability): νŠΈλžœμž­μ…˜μ΄ μ„±κ³΅λ˜μ—ˆλ‹€λ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ— 영ꡬ적으둜 λ°˜μ˜λ˜μ–΄μ•Ό ν•œλ‹€.

@Transactional

μŠ€ν”„λ§μ—μ„œλŠ” AOPλ₯Ό μ‚¬μš©ν•˜μ—¬ νŠΈλžœμž­μ…˜μ„ μ μš©ν•  수 μžˆλ‹€. @Transactional μ• λ…Έν…Œμ΄μ…˜μ„ ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œμ— μ‚¬μš©ν•˜λ©΄ μŠ€ν”„λ§μ€ ν•΄λ‹Ή ν΄λž˜μŠ€λ‘œλΆ€ν„° ν”„λ‘μ‹œ 객체λ₯Ό λ§Œλ“€μ–΄ μ»¨ν…Œμ΄λ„ˆμ— λ“±λ‘ν•œλ‹€. μŠ€ν”„λ§μ—μ„œμ˜ νŠΈλžœμž­μ…˜ λ™μž‘ 방식은 λ‹€μŒκ³Ό κ°™λ‹€.

  1. ν΄λΌμ΄μ–ΈνŠΈκ°€ ν”„λ‘μ‹œ 객체의 λ©”μ„œλ“œλ₯Ό 호좜
  2. ν”„λ‘μ‹œλŠ” ν•΄λ‹Ή λ©”μ„œλ“œκ°€ νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•  수 μžˆλŠ”μ§€ 확인
  3. νŠΈλžœμž­μ…˜ μ‹œμž‘
  4. μ‹€μ œ 객체의 λ©”μ„œλ“œ 호좜
  5. ν”„λ‘μ‹œλ‘œ μ œμ–΄κ°€ λŒμ•„μ˜€λ©΄ ν”„λ‘μ‹œλŠ” νŠΈλžœμž­μ…˜μ„ Commit ν•˜κ±°λ‚˜ Rollback

 ν”„λ‘μ‹œ λ‚΄λΆ€ 호좜

μœ„ μ„€λͺ…μ²˜λŸΌ @Transactional을 μ μš©ν•˜λ €λ©΄ 항상 ν”„λ‘μ‹œ 객체λ₯Ό ν†΅ν•΄μ„œ λŒ€μƒ 객체λ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€. ν”„λ‘μ‹œ κ°μ²΄μ—μ„œ λ¨Όμ € νŠΈλžœμž­μ…˜μ„ μ μš©ν•œ 이후에 λŒ€μƒ 객체λ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. μ΄λ•Œ ν”„λ‘μ‹œλ₯Ό κ±°μΉ˜μ§€ μ•Šκ³  λŒ€μƒ 객체λ₯Ό 직접 ν˜ΈμΆœν•˜κ²Œ 되면 AOPκ°€ μ μš©λ˜μ§€ μ•Šμ•„ @Transactional이 μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€. μ΄λŸ¬ν•œ 상황을 λ‚΄λΆ€ν˜ΈμΆœμ΄λΌκ³  ν•œλ‹€. μ½”λ“œλ‘œ 직접 확인해 보자.

νŠΈλžœμž­μ…˜ 둜그 λ ˆλ²¨μ„ λ””λ²„κ·Έλ‘œ μ„€μ •ν•˜λ©΄ νŠΈλžœμž­μ…˜μ˜ μ‹œμž‘κ³Ό 끝을 둜그둜 확인할 수 μžˆλ‹€.

logging.level:
  org.springframework.orm: debug

ν”„λ‘μ‹œ 객체 호좜

// TransactionService
@Transactional
public void outerTransaction() {
    log.info("TransactionService.outerTransaction");
}

// Test
@Test
void callOuterTransaction() {
    transactionService.outerTransaction();
}

ν”„λ‘μ‹œ 객체λ₯Ό ν†΅ν•΄μ„œ νŠΈλžœμž­μ…˜μ΄ 적용된 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ―€λ‘œ μ •μƒμ μœΌλ‘œ νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜λŠ” 것을 확인할 수 μžˆλ‹€.

ν”„λ‘μ‹œ λ‚΄λΆ€ 호좜

μ™ΈλΆ€ λ©”μ„œλ“œμ—μ„œ ν˜ΈμΆœν•  λ‚΄λΆ€ λ©”μ„œλ“œμ— νŠΈλžœμž­μ…˜μ˜ μ „νŒŒ 속성 REQUIERES_NEWλ₯Ό μ‚¬μš©ν•΄ 보자. μ΄λ‘ λŒ€λ‘œλΌλ©΄ μ™ΈλΆ€ λ©”μ„œλ“œ 호좜 μ‹œ νŠΈλžœμž­μ…˜μ΄ μ‹œμž‘λ˜κ³  λ‚΄λΆ€ λ©”μ„œλ“œ 호좜 μ‹œ 독립적인 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ΄ μ‹œμž‘λ˜μ–΄μ•Ό ν•œλ‹€.

// TransactionService
@Transactional
public void outerTransactionWithInnerTransaction() {
    log.info("TransactionService.outerTransactionWithInnerTransaction");
    innerTransaction();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerTransaction() {
    log.info("TransactionService.innerTransactional");
}

// Test
@Test
void callOuterTransactionWithInnerTransaction() {
    transactionService.outerTransactionWithInnerTransaction();
}

둜그λ₯Ό 확인해 보면 μ™ΈλΆ€ λ©”μ„œλ“œμ— λŒ€ν•΄μ„œλ§Œ νŠΈλžœμž­μ…˜μ΄ μ μš©λ˜μ—ˆλ‹€. λ‚΄λΆ€ νŠΈλžœμž­μ…˜μ΄ μ™ΈλΆ€λ‘œλΆ€ν„° λΆ„λ¦¬λ˜μ§€ μ•Šμ•˜κ³  일반 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 거와 λ™μΌν•˜κ²Œ λ™μž‘ν•œλ‹€. κ·Έ μ΄μœ λŠ” λ¬΄μ—‡μΌκΉŒ?

λ‚΄λΆ€ 호좜 μ‹œ @Transactional μ• λ…Έν…Œμ΄μ…˜μ΄ μ μš©λ˜μ§€ μ•ŠλŠ” 이유

μžλ°”μ—μ„œλŠ” λ©”μ„œλ“œ μ•žμ— λ³„λ„μ˜ μ°Έμ‘°κ°€ 없을 경우 thisλΌλŠ” 뜻으둜 자기 μžμ‹ μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό κ°€λ¦¬ν‚€κ²Œ λœλ‹€. thisλŠ” 자기 μžμ‹ μ„ κ°€λ¦¬ν‚€λŠ” μ‹€μ œ λŒ€μƒ 객체의 μΈμŠ€ν„΄μŠ€λ₯Ό μ˜λ―Έν•˜λ―€λ‘œ 결과적으둜 ν”„λ‘μ‹œλ₯Ό κ±°μΉ˜μ§€ μ•Šμ•„ @Transactional이 μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€. λ”°λΌμ„œ 일반 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것과 λ™μΌν•˜κ²Œ λ™μž‘ν•˜κ²Œ λ˜λŠ” 것이닀.

 ν•΄κ²° 방법

μœ„ λ‚΄μš©μ„ μ΄ν•΄ν–ˆλ‹€λ©΄ ν•΄κ²° 방법이 μ‰½κ²Œ λ– μ˜€λ₯Ό 것이닀. μ™ΈλΆ€ λ©”μ„œλ“œμ—μ„œ μ‹€μ œ λŒ€μƒ 객체가 μ•„λ‹Œ ν”„λ‘μ‹œ 객체λ₯Ό 톡해 λ‚΄λΆ€ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ„λ‘ μˆ˜μ •ν•˜λ©΄ λœλ‹€. InnerTransactionService λ₯Ό μƒμ„±ν•˜μ—¬ μ™ΈλΆ€ λ©”μ„œλ“œμ—μ„œ ν”„λ‘μ‹œλ₯Ό 톡해 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ„λ‘ μˆ˜μ •ν•΄ 보자.

// InnerTransactionService
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerTransaction() {
    log.info("InnerTransactionService.innerTransaction");
}

// TransactionService
@Transactional
public void outerTransactionWithInnerTransaction() {
    log.info("TransactionService.outerTransactionWithInnerTransaction");
    innerTransactionService.innerTransaction();
}

둜그λ₯Ό 확인해 보면 λ‚΄λΆ€ νŠΈλžœμž­μ…˜μ΄ μ™ΈλΆ€λ‘œλΆ€ν„° λΆ„λ¦¬λ˜μ–΄ μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ„ μƒμ„±ν•˜μ—¬ λ™μž‘ν•˜λŠ” 것을 확인할 수 μžˆλ‹€.

πŸ”š κ²°λ‘ 

μ§€κΈˆκΉŒμ§€ νŠΈλžœμž­μ…˜μ΄ ν•„μš”ν•˜λ©΄ 별생각 없이 @Transactional μ• λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬ μ‚¬μš©ν–ˆλŠ”λ°, 이번 기회둜 μŠ€ν”„λ§μ—μ„œ Transactional μ• λ…Έν…Œμ΄μ…˜μ΄ μ–΄λ–€ μ‹μœΌλ‘œ λ™μž‘ν•˜κ³  μ£Όμ˜ν•΄μ•Ό ν•  점이 무엇인지 ν•™μŠ΅ν•  수 μžˆμ—ˆλ‹€. μ•žμœΌλ‘œ νŠΈλžœμž­μ…˜μ΄ μ˜λ„ν•œ λŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šκ±°λ‚˜ 적용되고 μžˆμ§€ μ•Šλ‹€λ©΄ λ‚΄λΆ€ν˜ΈμΆœμ„ ν•˜κ³  μžˆλŠ” 게 μ•„λ‹Œ 지 확인해 봐야겠닀.