[Spring] Transaction

DevelopHeoΒ·2025λ…„ 1μ›” 3일
0
post-thumbnail

πŸ“™ νŠΈλžœμž­μ…˜ (Transaction)

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

νŠΈλžœμž­μ…˜μ€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ μƒνƒœλ₯Ό λ³€ν™˜μ‹œν‚€λŠ” μž‘μ—…μ˜ λ‹¨μœ„λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.
μ‰½κ²Œ λ§ν•΄μ„œ λ°”λ‘œ 이전 컀밋 μ΄ν›„μ˜ μž‘μ—…λΆ€ν„°, μ΄λŸ°μ €λŸ° μž‘μ—… ν›„ μ΅œμ’…μ μœΌλ‘œ 컀밋을 λ‚ λ¦¬κΈ°κΉŒμ§€μ˜ 주기이닀.
즉, μ—¬λŸ¬ μž‘μ—…μ΄ ν•˜λ‚˜μ˜ 논리적 λ‹¨μœ„λ‘œ λ¬Άμ—¬μ„œ λͺ¨λ‘ μ„±κ³΅ν•˜κ±°λ‚˜ λͺ¨λ‘ μ‹€νŒ¨ν•˜λ„λ‘ 보μž₯ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

νŠΈλžœμž­μ…˜ μ˜ˆμ‹œ

온라인 μ‡Όν•‘λͺ°μ„ κ²°μ œν•  λ•Œ, 두가지 μž‘μ—…μ„ κ±°μ³μ•Όν•œλ‹€.

  1. νŒλ§€μ²˜μ— λˆμ„ 보내기
  2. νŒλ§€μ²˜μ—μ„œ 고객이 보낸 λˆμ„ λ°›κΈ°

μ € 두 μž‘μ—…μ΄ ν•œ νŠΈλžœμž­μ…˜μ΄λΌκ³  ν•˜μž.

  • 이 경우 고객이 νŒλ§€μ²˜μ— λˆμ„ λ³΄λƒˆλŠ”λ° νŒλ§€μ²˜μ—μ„œ 고객이 보낸 λˆμ„ λ°›μ§€ λͺ»ν•˜λŠ” κ²½μš°λ‚˜, 고객이 λˆμ„ 보내지 μ•Šμ•˜λŠ”λ° νŒλ§€μ²˜μ—μ„œ λˆμ„ λ°›λŠ” κ²½μš°κ°€ 생기면 μ•ˆλœλ‹€.
  • λͺ¨λ“  μž‘μ—…μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλ˜μ–΄μ•Ό μž‘μ—… κ²°κ³Όλ₯Ό 적용(commit)ν•˜κ³ , νŠΈλžœμž­μ…˜μ— μ†ν•œ λͺ¨λ“  μž‘μ—… 쀑에(1λ²ˆμ΄λ‚˜ 2번 λ‘˜μ€‘μ—) ν•˜λ‚˜λΌλ„ 였λ₯˜κ°€ λ°œμƒν•˜λŠ” κ²½μš°μ—λŠ” μž‘μ—…μ„ μ‹€ν–‰ν•˜κΈ° μ „μ˜ μƒνƒœλ‘œ μ™„λ²½ν•˜κ²Œ λŒμ•„κ°€μ•Ό ν•˜λŠ” 것(rollback)이 νŠΈλžœμž­μ…˜μ˜ κ°œλ…μ΄λ‹€.

κ΅¬λ§€μžκ°€ νŒλ§€μ²˜μ—κ²Œ κΈˆμ•‘μ†‘κΈˆ ν•˜λŠ” 것을 μ½”λ“œλ‘œ κ΅¬ν˜„

1) νŠΈλžœμž­μ…˜ 자체λ₯Ό μ μš©ν•˜μ§€ μ•Šμ€ 경우

@Autowired
private Buyer buyer

@Autowired
private Seller seller;

public void buy() {

  buyer.send();			
  seller.receive();
      
}

μ΄λŸ¬ν•œ 경우 λ¬Έμ œκ°€ 생길 수 μžˆλŠ” 뢀뢄이

receive() λ©”μ†Œλ“œ μžμ²΄μ— λ¬Έμ œκ°€ μžˆμ–΄μ„œ 항상 send() κΉŒμ§€λŠ” 맀번 싀행이 되고 receive() λ©”μ†Œλ“œλŠ” 싀행이 λ˜μ§€ μ•Šμ„ 경우

κ΅¬λ§€μžλŠ” λˆμ„ λ³΄λ‚΄μ„œ DB상에 κΈˆμ•‘μ΄ μ€„μ–΄λ“€μ—ˆλŠ”λ°, νŒλ§€μžλŠ” μž…κΈˆμ΄ λ˜μ§€ μ•Šμ•„ DB상에 κΈˆμ•‘ 변동이 μ—†λŠ” κ²½μš°μ΄λ‹€.

λ”°λΌμ„œ λ°˜λ“œμ‹œ transaction을 κ±Έμ–΄μ„œ, receive() κ°€ μ‹€ν–‰λ˜μ§€ λͺ»ν•˜κ³  μ—λŸ¬κ°€ λ‚œ 경우 λ°˜λ“œμ‹œ send() λ˜ν•œ λ‘€λ°±λ˜μ–΄ 원상볡ꡬ μ‹œμΌœμ£Όμ–΄μ•Ό ν•œλ‹€.


2) @Transactional λŒ€μ‹  try-catch둜 κ΅¬ν˜„ν•œ 경우

@Autowired
private PlatformTransactionManager transactionManager;

@Autowired
private Buyer buyer

@Autowired
private Seller seller;

public void buy() {

  DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  TransactionStatus status = transactionManager.getTransaction(def);

  try {
      buyer.send();			
      seller.receive();
      
      transactionManager.commit(status);

  } catch(Exception e) {

      transactionManager.rollback(status);

  } 
}

TransactionManager둜 직접 컀밋과 둀백을 μ‹œμΌœμ£Όμ—ˆλ‹€.

κ·ΈλŸ¬λ‚˜ 쿼리λ₯Ό μ‚¬μš©ν•˜λŠ” λ©”μ†Œλ“œμ— 맀번 μ€‘λ³΅λ˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•΄ μ£Όμ–΄μ•Ό ν•˜λŠ” λΆˆνŽΈν•¨μ΄ μžˆλ‹€.


3) @Transactional을 μ‚¬μš©ν•œ 경우

@Autowired
private Buyer buyer

@Autowired
private Seller seller;

@Transactional
public void buy() {

  buyer.send();			
  seller.receive();

}

μ‚¬μš©λ  λ©”μ„œλ“œ μœ„μ— @Transactional μ–΄λ…Έν…Œμ΄μ…˜λ§Œ λΆ™μ—¬μ£Όλ©΄, μœ„μ˜ try-catch문을 μž‘μ„±ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.


4) λͺ¨λ“  λ©”μ†Œλ“œμ— @Transactional μ‚¬μš©ν•˜κ³  싢을 λ•Œ

@Transactional
public class AllQuery {

  public void selectOne() { }
  public int allCount() { }
  public List<User> allUser() { }  
  
  /* μ•„λž˜μ™€ λ™μΌν•˜λ‹€
  @Transactional
  public void selectOne() { }
  
  @Transactional
  public int allCount() { }
  
  @Transactional
  public List<User> allUser() { }  
  */  

}

λ§Œμ•½ μœ„μ™€ 같이 ν΄λž˜μŠ€μ— μ†ν•˜λŠ” λͺ¨λ“  λ©”μ†Œλ“œμ— @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ μš©ν•˜κ³  μ‹Άλ‹€λ©΄, μ–΄λ…Έν…Œμ΄μ…˜μ„ 클래슀 μœ„μ— λΆ™μ—¬μ€€λ‹€.

클래슀 μœ„μ— @Transactional이 λΆ™μ–΄μžˆμœΌλ©΄, ν΄λž˜μŠ€μ— μ†ν•œ λͺ¨λ“  λ©”μ†Œλ“œμ— 각각 @Transactional이 λΆ™μ–΄μžˆλ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€.

πŸ“™ νŠΈλžœμž­μ…˜μ˜ νŠΉμ§•(Transaction ACID)

"A"tomicity(μ›μžμ„±)

  • νŠΈλžœμž­μ…˜μ˜ 연산은 DB에 λͺ¨λ‘ λ°˜μ˜λ˜κ±°λ‚˜, λͺ¨λ‘ λ°˜μ˜λ˜μ§€ μ•Šμ•„μ•Όν•œλ‹€.
  • ν•˜λ‚˜λΌλ„ μ‹€νŒ¨ν•œλ‹€λ©΄, μ•žμ„œ μ„±κ³΅ν•œ 것듀을 λ³΅κ΅¬μ‹œμΌœμ•Όν•œλ‹€.

"C"onsistency(일관성)

νŠΈλžœμž­μ…˜ μ „ν›„μ˜ 데이터 μƒνƒœλŠ” 일관성을 μœ μ§€ν•΄μ•Ό ν•©λ‹ˆλ‹€.
예λ₯Ό λ“€μ–΄, 은행 κ³„μ’Œ μ΄μ²΄μ—μ„œ μ†‘κΈˆν•œ κΈˆμ•‘κ³Ό 받은 κΈˆμ•‘μ€ 항상 κ°™μ•„μ•Ό ν•©λ‹ˆλ‹€. (ex: DB의 무결성 μ œμ•½ 쑰건 항상 만쑱)

"I"solation(격리성)

μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ΄ λ™μ‹œμ— μ‹€ν–‰λ˜λ”λΌλ„ μ„œλ‘œ κ°„μ„­ν•˜μ§€ μ•Šλ„λ‘ 보μž₯ν•©λ‹ˆλ‹€. (ex: λ™μ‹œμ— 같은 데이터 μˆ˜μ • X)

"D"urability(지속성)

  • νŠΈλžœμž­μ…˜μ΄ μ™„λ£Œλœ μ΄ν›„μ—λŠ” μ‹œμŠ€ν…œ 였λ₯˜κ°€ λ°œμƒν•΄λ„ 데이터가 μœ μ§€λ©λ‹ˆλ‹€.
  • νŠΈλžœμž­μ…˜μ΄ μ™„λ£Œλœλ‹€λ©΄, κ²°κ³ΌλŠ” μ˜κ΅¬μ μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€.

πŸ“™ Springμ—μ„œ μ œκ³΅ν•˜λŠ” νŠΈλžœμž­μ…˜

νŠΈλžœμž­μ…˜ 격리 μˆ˜μ€€(Isolation Level)

λΉ„μ¦ˆλ‹ˆμŠ€ 둜직과 νŠΈλžœμž­μ…˜ 처리 둜직이 λ™μ‹œμ— μ‘΄μž¬ν•œλ‹€λ©΄ μ½”λ“œμ˜ 쀑볡이 λ°œμƒν•  μˆ˜λ„ 있고, λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ—λ§Œ μ§‘μ€‘λœ μ½”λ“œλ₯Ό μž‘μ„±ν•˜κΈ° μ–΄λ ΅λ‹€. μ΄λ ‡κ²Œ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ—λ§Œ μ§‘μ€‘ν•˜κΈ° μœ„ν•΄ Spring은 크게 2κ°€μ§€ νŠΈλžœμž­μ…˜ κΈ°μˆ μ„ μ§€μ›ν•œλ‹€.

1. κ°œλ°œμ‹ νŠΈλžœμž­μ…˜ = TransactionTemplate(TransactionManager을 μ£Όμž…λ°›μ•„ μ‚¬μš©)

  • νŠΈλžœμž­μ…˜ κ΄€λ ¨ μ½”λ“œλ₯Ό 직접 μž‘μ„±ν•˜λŠ” 방법
  • νŠΈλžœμž­μ…˜ λ§€λ‹ˆμ €μ—μ„œ νŠΈλžœμž­μ…˜μ„ μ–»μ–΄μ˜€λŠ” 방법
  • 가독성을 λ–¨μ–΄λœ¨λ¦¬κ³ , νœ΄λ¨Όμ—λŸ¬κ°€ 유발될 수 μžˆμœΌλ―€λ‘œ 잘 μ‚¬μš©ν•˜μ§€ μ•ŠμŒ.

2. 선언적 νŠΈλžœμž­μ…˜ (μ–΄λ…Έν…Œμ΄μ…˜, @Transactional)

- μŠ€ν”„λ§μ˜ AOPλ₯Ό 적극적으둜 체감가λŠ₯
- xmlμ—μ„œ AOP μ„€μ •μœΌλ‘œ νŠΈλžœμž­μ…˜μ„ μ„ μ–Έν•˜λŠ” 방법
- μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš©λ°©λ²•(@Transactional)

AOP(Aspect-Oriented Programming)

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κΈ°λŠ₯은 크게 핡심 κΈ°λŠ₯κ³Ό λΆ€κ°€ κΈ°λŠ₯으둜 λ‚˜λˆŒ 수 μžˆλ‹€.

  • 핡심 κΈ°λŠ₯: ν•΄λ‹Ή 객체가 μ œκ³΅ν•˜λŠ” κ³ μœ ν•œ κΈ°λŠ₯(λΉ„μ¦ˆλ‹ˆμŠ€ 둜직)(ex: UserService - μœ μ € κ΄€λ ¨ 둜직)

  • λΆ€κ°€ κΈ°λŠ₯: 핡심 κΈ°λŠ₯을 λ³΄μ‘°ν•˜λŠ” κΈ°λŠ₯(ex: 둜그 좔적, νŠΈλžœμž­μ…˜ 처리 λ“±)

λΆ€κ°€ κΈ°λŠ₯듀은 μ—¬λŸ¬ μ½”λ“œμ—μ„œ μž¬μ‚¬μš©λ˜λŠ” κ²½μš°κ°€ λ§Žλ‹€. 예λ₯Όλ“€μ–΄ TransactionManagerλ₯Ό μ΄μš©ν•΄ νŠΈλžœμž­μ…˜ 처리λ₯Ό ν•΄μ€€λ‹€λ©΄ ν•œλ²ˆμ— μ²˜λ¦¬λ˜μ–΄μ•Ό ν•˜λŠ” μž‘μ—…λ“€μ΄ μžˆλŠ” λͺ¨λ“  λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— commit ν•΄μ£Όκ³  rollbackν•΄μ£ΌλŠ” μ½”λ“œλ₯Ό λ°˜λ³΅ν•΄μ„œ μž‘μ„±ν•΄μ£Όμ–΄μ•Όν•œλ‹€.
-> μ΄λŸ¬ν•œ λΆ€κ°€ κΈ°λŠ₯듀을 λΆ„λ¦¬ν•˜κ³  어디에 μ μš©ν• μ§€ μ„ νƒν•˜λŠ” κΈ°λŠ₯을 합쳐 ν•˜λ‚˜μ˜ λͺ¨λ“ˆλ‘œ λ§Œλ“ κ²ƒμ΄ Aspect이닀.

-> μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ 바라볼 λ•Œ 핡심 κΈ°λŠ₯에 집쀑할 수 μžˆλ„λ‘ λ„μ™€μ£ΌλŠ” λͺ¨λ“ˆμ΄λΌκ³  μ΄ν•΄ν•˜λ©΄ μ’‹λ‹€.
=> @Transactional은 AOPλ₯Ό μ§€ν–₯ν•  수 μžˆλ„λ‘ μŠ€ν”„λ§μ—μ„œ μ§€μ›ν•΄μ£ΌλŠ” μ–΄λ…Έν…Œμ΄μ…˜μ΄λ‹€.

@Transactionalμ΄λž€?

@Transactional μ–΄λ…Έν…Œμ΄μ…˜μ€, ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ΄ μ μš©λ˜λŠ” λ©”μ†Œλ“œλ₯Ό ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬Άμ–΄μ£ΌλŠ” 역할을 ν•œλ‹€.

  • κ°œλ³„ λ©”μ†Œλ“œλ‚˜ ν΄λž˜μŠ€μ— 뢙을 수 μžˆλŠ” νŠΈλžœμž­μ…˜ νŠΉμ„±.
  • class레벨의 μ–΄λ…Έν…Œμ΄μ…˜μ€ μ„ μ–Έλœ ν΄λž˜μŠ€μ™€ 그의 μ„œλΈŒν΄λž˜μŠ€ 내뢀에 μžˆλŠ” λͺ¨λ“  λ©”μ†Œλ“œμ— μ μš©λœλ‹€.
  • 쑰상 클래슀둜 μ˜¬λΌκ°€ μ μš©λ˜μ§€λŠ” μ•ŠλŠ”λ‹€κ³  ν•œλ‹€!

@Transactioal λ™μž‘ ꡬ쑰

μŠ€ν”„λ§μ˜ νŠΈλžœμž­μ…˜ AOPλŠ” @Transactional을 μΈμ‹ν•˜μ—¬ νŠΈλžœμž­μ…˜ ν”„λ‘μ‹œλ₯Ό 적용.
ν”„λ‘μ‹œλŠ” 'λŒ€λ¦¬μΈ'μ΄λΌλŠ” 뜻으둜 Aspect와 @Transactional을 μ μš©ν•œ 클래슀 / λ©”μ„œλ“œμΈ Target을 μ—°κ²°ν•΄μ£ΌλŠ” μ—­ν• 

  1. ν΄λΌμ΄μ–ΈνŠΈκ°€ API 호좜

  2. ν”„λ‘μ‹œ μ‹€ν–‰

  3. νŠΈλžœμž­μ…˜ μ½”λ“œ μ‹€ν–‰

  4. λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ‹€ν–‰

  5. νŠΈλžœμž­μ…˜ μ½”λ“œ μ‹€ν–‰(commit / rollback)

πŸ“™ νŠΈλžœμž­μ…˜ μž‘λ™ κ³Όμ •

  1. μ‹œμž‘: νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.

    • Springμ—μ„œλŠ” @Transactional μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.
  2. μž‘μ—… μˆ˜ν–‰: λ°μ΄ν„°λ² μ΄μŠ€μ— ν•„μš”ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

    • SQL μ‹€ν–‰, INSERT/UPDATE/DELETE λ“±.
  3. 컀밋: λͺ¨λ“  μž‘μ—…μ΄ μ„±κ³΅ν•˜λ©΄ νŠΈλžœμž­μ…˜ κ²°κ³Όλ₯Ό λ°˜μ˜ν•©λ‹ˆλ‹€.

  4. λ‘€λ°±: μž‘μ—… 쀑 ν•˜λ‚˜λΌλ„ μ‹€νŒ¨ν•˜λ©΄ 이전 μƒνƒœλ‘œ λ˜λŒλ¦½λ‹ˆλ‹€.

좜처

0개의 λŒ“κΈ€