Contents

Spring Transaction μ˜΅μ…˜

β€» 쿠팑 νŒŒνŠΈλ„ˆμŠ€ ν™œλ™μ„ 톡해 μΌμ •μ•‘μ˜ 수수료λ₯Ό μ œκ³΅λ°›μ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

상황

μŠ€ν”„λ§ ν™˜κ²½μ—μ„œ 일반적으둜 DAO λ‚˜ BO λ ˆλ²¨μ—μ„œ λ‹€μŒκ³Ό 같이 코딩을 ν•˜κ²Œ λœλ‹€.

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public int method(int i) throws Exception {
	return sqlMapClient.delete("~~~~");
}

λ¬΄λΆ„λ³„ν•˜κ²Œ Ctrl+C,V μ‹ κ³΅μœΌλ‘œ νŠΈλžœμž­μ…˜ μ–΄λ…Έν…Œμ΄μ…˜μ„ κ°€μ Έλ‹€κ°€ μ‚¬μš©ν• μˆ˜λ„ μžˆκ² μœΌλ‚˜, 각 값듀이 μ–΄λ–€ μ—­ν™œμ„ μ•„λŠ”μ§€μ— λŒ€ν•΄ μ•Œκ³  λ„˜μ–΄κ°ˆ ν•„μš”μ„±μ΄ μžˆλ‹€.

@Transactional

μš°μ„  ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ„ μ μš©ν•˜λ©΄ 적용된 클래슀 λ˜λŠ” λ©”μ†Œλ“œμ— νŠΈλžœμž­μ…˜μ΄ μ μš©λœλ‹€. λ”°λΌμ„œ 둜직 흐름에 λ§žμΆ”μ–΄ μ „μ²΄μ μœΌλ‘œ νŠΈλžœμž­μ…˜μ„ μ μš©ν• κ²ƒμΈμ§€, μ•„λ‹ˆλ©΄ νŠΉμ • λ©”μ†Œλ“œμ— μ μš©ν• κ²ƒμΈμ§€ μ „λž΅μ„ 잘 μ„Έμ›Œμ•Ό ν•œλ‹€.

isolation

κ²©λ¦¬μˆ˜μ€€μ΄λΌλŠ” μ˜΅μ…˜μ΄λ‹€. νŠΈλžœμž­μ…˜μ—μ„œ 일관성이 μ—†λŠ” 데이터λ₯Ό ν—ˆμš©ν•˜λ„λ‘ ν•˜λŠ” μˆ˜μ€€μ„ λ§ν•˜λŠ”λ° μ˜΅μ…˜μ€ λ‹€μŒκ³Ό κ°™λ‹€.

  1. READ_UNCOMMITTED (level 0)
  • νŠΈλžœμž­μ…˜μ— μ²˜λ¦¬μ€‘μΈ ν˜Ήμ€ 아직 μ»€λ°‹λ˜μ§€ μ•Šμ€ 데이터λ₯Ό λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ΄ μ½λŠ” 것을 ν—ˆμš©
  • μ–΄λ–€ μ‚¬μš©μžκ°€ AλΌλŠ” 데이터λ₯Ό BλΌλŠ” λ°μ΄ν„°λ‘œ λ³€κ²½ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μ‚¬μš©μžλŠ” BλΌλŠ” 아직 μ™„λ£Œλ˜μ§€ μ•Šμ€(Uncommitted ν˜Ήμ€ Dirty) 데이터 Bλ₯Ό 읽을 수 μžˆλ‹€.

    Dirty read : μœ„μ™€ 같이 λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ—μ„œ μ²˜λ¦¬ν•˜λŠ” μž‘μ—…μ΄ μ™„λ£Œλ˜μ§€ μ•Šμ•˜λŠ”λ°λ„ λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ—μ„œ λ³Ό 수 μžˆλŠ” ν˜„μƒμ„ dirty read 라고 ν•˜λ©°, READ UNCOMMITTED κ²©λ¦¬μˆ˜μ€€μ—μ„œλ§Œ μΌμ–΄λ‚˜λŠ” ν˜„μƒ

  1. READ_COMMITTED (level 1)
  • dirty read 방지 : νŠΈλžœμž­μ…˜μ΄ μ»€λ°‹λ˜μ–΄ ν™•μ •λœ λ°μ΄ν„°λ§Œμ„ μ½λŠ” 것을 ν—ˆμš©
  • μ–΄λ– ν•œ μ‚¬μš©μžκ°€ AλΌλŠ” 데이터λ₯Ό BλΌλŠ” λ°μ΄ν„°λ‘œ λ³€κ²½ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μ‚¬μš©μžλŠ” ν•΄λ‹Ή 데이터에 μ ‘κ·Όν•  수 μ—†λ‹€.
  1. REPEATABLE_READ (level 2)
  • νŠΈλžœμž­μ…˜μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ SELECT λ¬Έμž₯이 μ‚¬μš©ν•˜λŠ” λͺ¨λ“  데이터에 shared lock이 κ±Έλ¦¬λ―€λ‘œ λ‹€λ₯Έ μ‚¬μš©μžλŠ” κ·Έ μ˜μ—­μ— ν•΄λ‹Ήλ˜λŠ” 데이터에 λŒ€ν•œ μˆ˜μ •μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€.
  • μ„ ν–‰ νŠΈλžœμž­μ…˜μ΄ 읽은 λ°μ΄ν„°λŠ” νŠΈλžœμž­μ…˜μ΄ μ’…λ£Œλ  λ•ŒκΉŒμ§€ ν›„ν–‰ νŠΈλžœμž­μ…˜μ΄ κ°±μ‹ ν•˜κ±°λ‚˜ μ‚­μ œν•˜λŠ” 것을 λΆˆν—ˆν•¨μœΌλ‘œμ¨ 같은 데이터λ₯Ό 두 번 μΏΌλ¦¬ν–ˆμ„ λ•Œ 일관성 μžˆλŠ” κ²°κ³Όλ₯Ό 리턴함
  1. SERIALIZABLE (level 3)
  • μ™„λ²½ν•œ 읽기 일관성 λͺ¨λ“œλ₯Ό 제곡
  • λ°μ΄ν„°μ˜ 일관성 및 λ™μ‹œμ„±μ„ μœ„ν•΄ MVCC(Multi Version Concurrency Control)을 μ‚¬μš©ν•˜μ§€ μ•ŠμŒ(MVCCλŠ” 닀쀑 μ‚¬μš©μž λ°μ΄ν„°λ² μ΄μŠ€ μ„±λŠ₯을 μœ„ν•œ 기술둜 데이터 쑰회 μ‹œ LOCK을 μ‚¬μš©ν•˜μ§€ μ•Šκ³  λ°μ΄ν„°μ˜ 버전을 관리해 λ°μ΄ν„°μ˜ 일관성 및 λ™μ‹œμ„±μ„ λ†’μ΄λŠ” 기술)
  • νŠΈλžœμž­μ…˜μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ SELECT λ¬Έμž₯이 μ‚¬μš©ν•˜λŠ” λͺ¨λ“  데이터에 shared lock이 κ±Έλ¦¬λ―€λ‘œ λ‹€λ₯Έ μ‚¬μš©μžλŠ” κ·Έ μ˜μ—­μ— ν•΄λ‹Ήλ˜λŠ” 데이터에 λŒ€ν•œ μˆ˜μ • 및 μž…λ ₯이 λΆˆκ°€λŠ₯ν•˜λ‹€.

propagation ( μ „νŒŒμ˜΅μ…˜)

  • REQUIRED : λΆ€λͺ¨ νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μ‹€ν–‰ν•˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ 없을 경우 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ„ 생성
  • REQUIRES_NEW : λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ„ λ¬΄μ‹œν•˜κ³  무쑰건 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ΄ 생성
  • SUPPORT : λΆ€λͺ¨ νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μ‹€ν–‰ν•˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ 없을 경우 nontransactionally둜 μ‹€ν–‰
  • MANDATORY : λΆ€λͺ¨ νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μ‹€ν–‰λ˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ 없을 경우 μ˜ˆμ™Έκ°€ λ°œμƒ
  • NOT_SUPPORT : nontransactionally둜 μ‹€ν–‰ν•˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ 싀행될 경우 μΌμ‹œ 정지
  • NEVER : nontransactionally둜 μ‹€ν–‰λ˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•œλ‹€λ©΄ μ˜ˆμ™Έκ°€ λ°œμƒ
  • NESTED : ν•΄λ‹Ή λ©”μ„œλ“œκ°€ λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ—μ„œ 진행될 경우 λ³„κ°œλ‘œ μ»€λ°‹λ˜κ±°λ‚˜ 둀백될 수 있음. λ‘˜λŸ¬μ‹Ό νŠΈλžœμž­μ…˜μ΄ 없을 경우 REQUIRED와 λ™μΌν•˜κ²Œ μž‘λ™

no-rollback-for - μ˜ˆμ™Έμ²˜λ¦¬ (κΈ°λ³Έκ°’ : μ—†μŒ)

νŠΉμ • μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ”λΌλ„ λ‘€λ°±λ˜μ§€ μ•Šλ„λ‘ μ„€μ •

μŠ€ν”„λ§ λ°°μΉ˜μ—μ„œμ˜ νŠΈλžœμž­μ…˜ (λ‚΄κ°€ λ‹Ήν–ˆλ˜(?) 문제)

μŠ€ν”„λ§ λ°°μΉ˜μ—μ„œλŠ” Tasklet μ—μ„œ 기본적으둜 step λ‹¨μœ„ νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜κ³  μžˆλ‹€κ³  ν•œλ‹€. 기본적으둜 job이 ν•˜λ‚˜μ˜ tasklet 의 step 으둜 μ‹€ν–‰ν•˜λ‹€λ³΄λ‹ˆ λͺ…μ‹œμ μ΄μ§„ μ•Šμ§€λ§Œ λ‚΄λΆ€μ μœΌλ‘œ 전체 νŠΈλžœμž­μ…˜μœΌλ‘œ 걸렀있게 λœλ‹€. λ‚˜κ°™μ€ job λ‚΄ DAO delete λ©”μ†Œλ“œμ—μ„œ @Transactional 섀정을 ν•˜κ³  κ·Έ DAO λ©”μ†Œλ“œλ₯Ό λ°˜λ³΅λ¬Έμ— μ˜ν•΄ delete ν•˜λŠ” λ‘œμ§μ„ μˆ˜ν–‰ν•˜λŠ” 뢀뢄이 μžˆμ—ˆλŠ”λ° λΆ€λͺ¨μ˜ νŠΈλžœμž­μ…˜(taskletμ—μ„œ μ„€μ •λœ νŠΈλžœμž­μ…˜)으둜 인해 dao λ₯Ό λͺ‡λ²ˆ ν˜ΈμΆœν•˜λ˜ jobλ‹¨μœ„λ‘œ νŠΈλ Œμ μ…˜μ΄ 걸리게 λ˜μ—ˆλ‹€. (κ²°κ΅­ νŠΈλžœμž­μ…˜μ€ 반볡문이 λ‹€ λλ‚˜μ•Ό 적용이 λœλ‹€λŠ”μ .) κ·ΈλŸ¬λ‹€λ³΄λ‹ˆ 가끔 DB Query Lock이 κ±Έλ ΈλŠ”λ° DBλ ˆλ²¨μ—μ„œ undologλ₯Ό λ‚¨κΈ°λŠ”κ²Œ λ„ˆλ¬΄ λ¬΄κ±°μ›Œμ Έ lock이 λ°œμƒ

λ”°λΌμ„œ μ „νŒŒμ˜΅μ…˜μ„ μˆ˜μ •ν•΄μ„œ ν•΄λ‹Ή 문제λ₯Ό ν•΄κ²°ν•˜μ˜€λ‹€.

# κΈ°μ‘΄
begin  
delete < for 반볡문
commit

# μ „νŒŒμ˜΅μ…˜ μˆ˜μ • (κΈ°μ‘΄ REQUIRES μ—μ„œ REQUIRES_NEW 으둜 μˆ˜μ •)
for
 begin
     delete
 commit
for end  

β€» 쿠팑 νŒŒνŠΈλ„ˆμŠ€ ν™œλ™μ„ 톡해 μΌμ •μ•‘μ˜ 수수료λ₯Ό μ œκ³΅λ°›μ„ 수 μžˆμŠ΅λ‹ˆλ‹€.


Buy me a coffeeBuy me a coffee