Skip to content

Latest commit

Β 

History

History
101 lines (100 loc) Β· 8.24 KB

@Transactional.md

File metadata and controls

101 lines (100 loc) Β· 8.24 KB

@Transactional

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

  • DB νŠΈλžœμž­μ…˜μ΄λž€, DB 관리 μ‹œμŠ€ν…œ λ˜λŠ” μœ μ‚¬ν•œ μ‹œμŠ€ν…œμ—μ„œμ˜ μƒν˜Έμž‘μš©μ˜ λ‹¨μœ„μ΄λ‹€.
    • λ‹¨μœ„ : 더 이상 μͺΌκ°œμ§ˆ 수 μ—†λŠ” μ΅œμ†Œμ˜ μ—°μ‚°
  • 결제 μž‘μ—…μ„ νŠΈλžœμž­μ…˜ μ˜ˆμ‹œλ‘œ λ“€ 경우
    • κ²°μ œλŠ” λ‹€λ₯Έ μ‚¬λžŒκ³Ό λ…λ¦½μ μœΌλ‘œ 이루어지며 κ³Όμ • 쀑에 λ‹€λ₯Έ 연산이 끼어듀 수 μ—†λ‹€. 였λ₯˜κ°€ 생긴 경우 연산을 μ·¨μ†Œν•˜κ³  μ›λž˜λŒ€λ‘œ λ˜λŒλ¦°λ‹€. 성곡할 경우 κ²°κ³Όλ₯Ό λ°˜μ˜ν•œλ‹€.
    • νŠΈλžœμž­μ…˜μ˜ 원칙 : ACID (μ›μžμ„±, 일관성, 고립성, 지속성)

@Transactional μ–΄λ…Έν…Œμ΄μ…˜

  • ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œμ— 뢙일 경우, ν•΄λ‹Ή λ²”μœ„ λ‚΄ λ©”μ„œλ“œκ°€ νŠΈλžœμž­μ…˜μ΄ λ˜λ„λ‘ 보μž₯ν•΄μ€€λ‹€.
    • 선언적 νŠΈλžœμž­μ…˜ : 직접 객체λ₯Ό λ§Œλ“€ ν•„μš” 없이 μ„ μ–Έλ§ŒμœΌλ‘œλ„ 관리λ₯Ό μš©μ΄ν•˜κ²Œ ν•΄μ€Œ
  • 예제 μ½”λ“œ
@RequiredArgsConstruct
@Service
public class MemberService {
	private final MemberRepository memberRepository;
	
	@Transactional(readOnly = true)
	public List<MemberResponseEntity> getMembers() {
		return bookRepository.findAll();
	}
}
  • getMembers() λ©”μ„œλ“œλŠ” μ•„λž˜μ™€ 같은 속성을 κ°€μ§„λ‹€.
    • 연산이 κ³ λ¦½λ˜μ–΄ λ‹€λ₯Έ μ—°μ‚°κ³Όμ˜ ν˜Όμ„ μœΌλ‘œ 인해 잘λͺ»λœ 값을 κ°€μ Έμ˜€λŠ” κ²½μš°κ°€ λ°©μ§€λœλ‹€.
    • μ—°μ‚°μ˜ μ›μžμ„±μ΄ 보μž₯λ˜μ–΄ 연산이 도쀑에 μ‹€νŒ¨ν•  경우 변경사항이 λ°˜μ˜λ˜μ§€ μ•ŠλŠ”λ‹€.
  • λ”°λΌμ„œ ν•΄λ‹Ή λ©”μ„œλ“œκ°€ μ‹€ν–‰λ˜λŠ” 도쀑 λ©”μ„œλ“œ 값을 μˆ˜μ • λ˜λŠ” μ‚­μ œν•˜λ €λŠ” μ‹œλ„κ°€ 듀어와도 κ°’μ˜ 신뒰성이 보μž₯λœλ‹€.

@Transactional μž‘λ™ 원리 및 ν”„λ‘œμ„ΈμŠ€

  • @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ΄ 클래슀 λ˜λŠ” λ©”μ„œλ“œμ— 뢙을 경우 Spring이 ν•΄λ‹Ή λ©”μ„œλ“œμ— λŒ€ν•˜μ—¬ ν”„λ‘μ‹œλ₯Ό λ§Œλ“ λ‹€.
    • ν”„λ‘μ‹œ νŒ¨ν„΄
    • μ–΄λ–€ μ½”λ“œλ₯Ό κ°μ‹Έλ©΄μ„œ 좔가적인 연산을 μˆ˜ν–‰ν•˜λ„λ‘ κ°•μ œν•˜λŠ” νŒ¨ν„΄
  • νŠΈλžœμž­μ…˜μ˜ 경우 μ‹œμž‘κ³Ό μ—°μ‚° μ’…λ£Œ μ‹œμ˜ 컀밋 과정이 ν•„μš”ν•˜λ―€λ‘œ, ν”„λ‘μ‹œλ₯Ό 생성해 ν•΄λ‹Ή λ©”μ„œλ“œμ˜ μ•žλ’€μ— νŠΈλžœμž­μ…˜μ˜ μ‹œμž‘κ³Ό 끝을 μΆ”κ°€ν•˜λŠ” 것
  • λ˜ν•œ Spring μ»¨ν…Œμ΄λ„ˆλŠ” νŠΈλžœμž­μ…˜ λ²”μœ„μ˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ „λž΅μ„ 기본으둜 μ‚¬μš©ν•œλ‹€.
    • μ„œλΉ„μŠ€ ν΄λž˜μŠ€μ—μ„œ @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄, ν•΄λ‹Ή μ½”λ“œ λ‚΄μ˜ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μƒκΈ΄λ‹€λŠ” 의미

@Transactional μ–΄λ…Έν…Œμ΄μ…˜ μ˜΅μ…˜

  1. isolation
    • λ™μ‹œμ— μ—¬λŸ¬ μ‚¬μš©μžκ°€ 데이터에 μ ‘κ·Όν•  λ•Œ μ–΄λ””κΉŒμ§€ ν—ˆμš©ν• μ§€μ— λŒ€ν•˜μ—¬ μ •ν•˜λŠ” μ˜΅μ…˜
    • νŠΈλžœμž­μ…˜μ˜ 격리 μˆ˜μ€€κ³Ό λ°μ΄ν„°μ˜ 일관성은 λΉ„λ‘€
    • @Transactionalμ—μ„œλŠ” 5κ°€μ§€ isolation μ˜΅μ…˜ 제곡
      1. DEFAULT
        • κΈ°λ³Έ 격리 μˆ˜μ€€
      2. READ_UNCOMMITTED
        • ν•œ νŠΈλžœμž­μ…˜μ΄ 처리 쀑인 μ»€λ°‹λ˜μ§€ μ•Šμ€ 데이터λ₯Ό λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ΄ μ ‘κ·Ό κ°€λŠ₯ν•˜λ„λ‘ 함
        • DB에 μ»€λ°‹λ˜μ§€ μ•Šμ€, μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 데이터λ₯Ό μ½λŠ” ν˜„μƒμ„ Dirty Read 라고 함
        • Dirty Readκ°€ κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— 잘λͺ»λœ 데이터λ₯Ό 읽을 μˆ˜λ„ 있음
      3. READ_COMMITTED
        • μ»€λ°‹λœ λ°μ΄ν„°λ§Œ μ ‘κ·Ό κ°€λŠ₯ν•˜λ„λ‘ 함
        • Non-Repeatable Read ν˜„μƒμ΄ λ°œμƒν•  수 있음
          • νŠΈλžœμž­μ…˜μ—μ„œ μ‘°νšŒν•œ 데이터가 νŠΈλžœμž­μ…˜μ΄ λλ‚˜κΈ° μ „μ˜ λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ— μ˜ν•΄ λ³€κ²½λ˜λ©΄ λ‹€μ‹œ μ½μ—ˆμ„ λ•Œ λ‹€λ₯Έ 값이 읽히며 데이터간 λΆˆμΌμΉ˜κ°€ λ°œμƒν•˜λŠ” ν˜„μƒ
      4. REPEATABLE_READ
        • ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μ€ ν•˜λ‚˜μ˜ μŠ€λƒ…μƒ·λ§Œ μ‚¬μš©ν•˜λ„λ‘ 함
        • A νŠΈλžœμž­μ…˜μ΄ μ‹œμž‘ν•˜κ³  처음 μ‘°νšŒν•œ λ°μ΄ν„°μ˜ μŠ€λƒ…μƒ·μ„ μ €μž₯, 이후 λ™μΌν•œ 쿼리λ₯Ό ν˜ΈμΆœν•˜λ©΄ μŠ€λƒ…μƒ·μ—μ„œ 데이터λ₯Ό κ°€μ Έμ˜΄
        • Phantom Read ν˜„μƒμ΄ λ°œμƒν•  수 있음
          • λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ—μ„œ μˆ˜ν–‰ν•œ μž‘μ—…μ— μ˜ν•΄ μ•ˆλ³΄μ˜€λ˜ 데이터가 λ³΄μ΄λŠ” ν˜„μƒ
      5. SERIALIZABLE
        • κ°€μž₯ λ‹¨μˆœν•˜κ³  μ—„κ²©ν•œ 격리 μˆ˜μ€€
        • 순차적으둜 νŠΈλžœμž­μ…˜μ„ μ§„ν–‰μ‹œν‚€λ©° 읽기 μž‘μ—…μ—λ„ μž κΈˆμ„ κ±Έμ–΄ μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ΄ λ™μ‹œμ— 같은 데이터에 μ ‘κ·Όν•˜μ§€ λͺ»ν•˜κ²Œ 함
        • κ°€μž₯ μ•ˆμ „ν•˜μ§€λ§Œ μ„±λŠ₯ μ €ν•˜κ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— κ·Ήλ„μ˜ μ•ˆμ •μ„±μ„ ν•„μš”λ‘œ ν•˜μ§€ μ•Šμ„ 경우 자주 μ‚¬μš©ν•˜μ§€ μ•ŠμŒ
  2. propagation
    • ν˜„μž¬ 진행쀑인 νŠΈλžœμž­μ…˜ (λΆ€λͺ¨ νŠΈλžœμž­μ…˜) 이 μ‘΄μž¬ν•  λ•Œ μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  경우 μ–΄λ–€ 정책을 μ‚¬μš©ν•  μ§€ μ •μ˜ν•˜λŠ” 속성
    • @Transactionalμ—μ„œλŠ” 7κ°€μ§€ propagation μ˜΅μ…˜ 제곡
      1. REQUIRED
        • κΈ°λ³Έ κ°’μœΌλ‘œ, λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•  경우 μ°Έμ—¬ν•˜κ³  μ—†λŠ” 경우 μƒˆ νŠΈλžœμ Ήμ…˜ μ‹œμž‘
      2. SUPPORTS
        • λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•  경우 μ°Έμ—¬ν•˜κ³  μ—†λŠ” 경우 non-transactonal μƒνƒœλ‘œ μ‹€ν–‰
      3. MANDATORY
        • λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•  경우 μ°Έμ—¬ν•˜κ³  μ—†λŠ” 경우 μ˜ˆμ™Έ λ°œμƒ
      4. REQUIRES_NEW
        • λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ„ λ¬΄μ‹œν•˜κ³  무쑰건 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜μ΄ 생성
      5. NOT_SUPPORTED
        • non-transactional μƒνƒœλ‘œ μ‹€ν–‰ν•˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•˜λŠ” 경우 μΌμ‹œμ •μ§€
      6. NEVER
        • non-transactional μƒνƒœλ‘œ μ‹€ν–‰ν•˜λ©° λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•˜λŠ” 경우 μ˜ˆμ™Έ λ°œμƒ
      7. NESTED
        • λΆ€λͺ¨ νŠΈλžœμž­μ…˜κ³ΌλŠ” λ³„κ°œλ‘œ μ€‘μ²©λœ νŠΈλžœμž­μ…˜ 생성
        • λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ˜ 컀밋과 λ‘€λ°±μ—λŠ” 영ν–₯을 λ°›μ§€λ§Œ μžμ‹ μ˜ 컀밋과 둀백은 λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ— 영ν–₯ μ£Όμ§€ μ•ŠμŒ
        • λΆ€λͺ¨ νŠΈλžœμž­μ…˜μ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 경우 μƒˆλ‘œμš΄ νŠΈλžœμž­μ…˜ 생성 (REQUIRED)
        • DBκ°€ SAVEPOINTλ₯Ό 지원해야 μ‚¬μš© κ°€λŠ₯ (Oracle)
        • JpaTransactionManager μ—μ„œλŠ” μ§€μ›ν•˜μ§€ μ•ŠμŒ
  3. readOnly
    • 기본값은 falseλ©° true둜 μ„ΈνŒ…ν•˜λŠ” 경우 νŠΈλžœμž­μ…˜μ„ 읽기 μ „μš©μœΌλ‘œ 변경함
    • μ„±λŠ₯ ν–₯상을 μœ„ν•΄ μ‚¬μš©ν•˜κ±°λ‚˜ 읽기 μ™Έ λ‹€λ₯Έ λ™μž‘μ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜κΈ°λ„ 함
  4. rollbackFor
    • μ‚¬μš©λ²•: @Transactional(rollbackFor = {IOException.class, ClassNotFoundException.class})
    • μ‚¬μš© μ‹œ @Transactional(rollbackFor = IOException.class) 처럼 Exception을 ν•˜λ‚˜λ§Œ μ§€μ •ν•œλ‹€λ©΄ μ€‘κ΄„ν˜Έ μƒλž΅ κ°€λŠ₯
    • νŠΉμ • Exception λ°œμƒ μ‹œ 데이터λ₯Ό μ»€λ°‹ν•˜μ§€ μ•Šκ³  λ‘€λ°±ν•˜λ„λ‘ μ„€μ •
  5. timeout
    • μ‚¬μš©λ²•: @Transactional(timeout = 3)
    • μ§€μ •λœ μ‹œκ°„ 내에 ν•΄λ‹Ή λ©”μ„œλ“œ μˆ˜ν–‰μ΄ μ™„λ£Œλ˜μ§€ μ•ŠλŠ” 경우 JpaSystemException λ°œμƒ
    • JpaSystemException은 RuntimeException을 상속받기 λ•Œλ¬Έμ— λ°μ΄ν„°λŠ” λ‘€λ°± 처리됨
    • 초 λ‹¨μœ„λ‘œ μ§€μ •ν•  수 있으며 -1 κ°’μœΌλ‘œ μ§€μ •ν•  경우 timeout을 μ§€μ›ν•˜μ§€ μ•ŠμŒ

μ™œ @Transactional(readOnly = true) 섀정일 λ•Œ μ„±λŠ₯이 ν–₯μƒλ˜λŠ”κ°€?

  • JPA의 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μˆ˜ν–‰ν•˜λŠ” λ³€κ²½ 감지(Dirty Checking)와 관련이 μžˆλ‹€.
    • λ³€κ²½ 감지?
      • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” Entity 쑰회 μ‹œ 초기 μƒνƒœμ— λŒ€ν•œ μŠ€λƒ…μƒ·μ„ μ €μž₯ν•œλ‹€.
      • νŠΈλžœμž­μ…˜μ΄ Commit 될 λ•Œ, 초기 μƒνƒœμ˜ 정보λ₯Ό κ°€μ§€λŠ” μŠ€λƒ…μƒ·κ³Ό Entity의 μƒνƒœλ₯Ό λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ λ‚΄μš©μ— λŒ€ν•΄ update query 둜 μ“°κΈ° μ§€μ—° μ €μž₯μ†Œμ— μ €μž₯ν•œλ‹€.
      • κ·Έ ν›„ μΌκ΄„μ μœΌλ‘œ μ“°κΈ° μ§€μ—° μ €μž₯μ†Œμ— μ €μž₯λ˜μ–΄ μžˆλŠ” SQL queryλ₯Ό flush ν•˜κ³  λ°μ΄ν„°λ² μ΄μŠ€μ˜ νŠΈλžœμž­μ…˜μ„ Commit ν•¨μœΌλ‘œμ„œ, μš°λ¦¬κ°€ update와 같은 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ λ„ Entity의 μˆ˜μ •μ΄ 이루어진닀. 이λ₯Ό λ³€κ²½ 감지라고 ν•œλ‹€.
    • readOnly = true 둜 μ„€μ •ν•˜κ²Œ 되면 μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬λŠ” JPA의 μ„Έμ…˜ ν”ŒλŸ¬μ‹œ λͺ¨λ“œλ₯Ό μˆ˜λ™μœΌλ‘œ μ„€μ •ν•΄, μ‚¬μš©μžκ°€ μˆ˜λ™μœΌλ‘œ flush() ν˜ΈμΆœν•˜μ§€ μ•ŠμœΌλ©΄ flushκ°€ μˆ˜ν–‰λ˜μ§€ μ•Šκ²Œ ν•œλ‹€.
      • νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ κ°•μ œλ‘œ flush()λ₯Ό ν˜ΈμΆœν•˜μ§€ μ•ŠμœΌλ©΄, μˆ˜μ • 내역에 λŒ€ν•΄ DB에 μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.
      • 이둜 인해 νŠΈλžœμž­μ…˜ Commit μ‹œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μžλ™μœΌλ‘œ flush λ˜μ§€ μ•ŠμœΌλ―€λ‘œ 쑰회용으둜 κ°€μ Έμ˜¨ Entity의 μ˜ˆμƒμΉ˜ λͺ»ν•œ 였λ₯˜λ₯Ό λ°©μ§€ν•  수 μžˆλ‹€.
    • λ˜ν•œ readOnly = true λ₯Ό μ„€μ •ν•˜κ²Œ 되면 JPAλŠ” ν•΄λ‹Ή νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μ‘°νšŒν•˜λŠ” EntityλŠ” μ‘°νšŒμš©μž„μ„ μΈμ‹ν•˜κ³  λ³€κ²½ 감지λ₯Ό μœ„ν•œ μŠ€λƒ…μƒ·μ„ λ”°λ‘œ λ³΄κ΄€ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ λ©”λͺ¨λ¦¬κ°€ μ ˆμ•½λ˜λŠ” μ„±λŠ₯상 이점 λ˜ν•œ μ‘΄μž¬ν•˜κ²Œ λœλ‹€.