Spring

Transactional 심화 / Isolation (격리 수준)

sehunbang 2024. 3. 6. 19:58

Propagation (전파 전략)

 

1. PROPAGATION_REQUIRED ( JpaTransactionManager Default )

 

  • 부모 트랜잭션이 존재할 경우
    • 부모 트랜잭션에 참여한다.
  • 부모 트랜잭션이 없을 경우
    • 새 트랜잭션을 시작한다.

일반적으로 사용되는 트랜잭션의 전파유형이다.

 

즉, 어떻게 해서든 (상속받서든, 내가 새로만들든) Transaction 을 시작하는 전파 유형
작한다.

 

 

2. PROPAGATION_SUPPORTS

  • 부모 트랜잭션이 존재할 경우
    • 부모 트랜잭션에 참여한다.
  • 부모 트랜잭션이 없을 경우
    • non-transactional 하게 동작한다.
부모 따라서 전파되는 유형

3. PROPAGATION_MANDATORY

  • 부모 트랜잭션이 존재할 경우
    • 부모 트랜잭션에 참여한다.
  • 부모 트랜잭션이 없을 경우
    • Exception이 발생한다.

트랜잭션에 참여하도록 강제하는 유형

4. PROPAGATION_REQUIRES_NEW

  • 부모 트랜잭션 유무에 상관없이
    • 새 트랜잭션을 시작한다.
  • 부모 트랜잭션이 존재할 경우
    • 부모 트랜잭션을 중지 시킨다.

무조건 새 트랜잭션을 생성하도록 강제하는 유형

5. PROPAGATION_NOT_SUPPORTED

  • 부모 트랜잭션 유무에 상관없이
    • non-transactional 하게 동작한다.
  • 부모 트랜잭션이 존재할 경우
    • 부모 트랜잭션을 중지 시킨다.

6. PROPAGATION_NEVER

  • 부모 트랜잭션이 존재할 경우 Exception이 발생한다.

항상 non-transactional 하게 동작하는 유형

 

 

@RunWith(SpringRunner.class)
@SpringBootTest
public class TransTest {
  @Autowired
  Parent parent;

  @Test
  @Transactional(propagation = Propagation.NOT_SUPPORTED) // 트랜잭션 생성 방지
  public void transactionalPropagationTest() {
    parent.parentMethod(); // 부모 메서드 실행
  }
}

 

@Component
public class Parent {
  @Autowired
  Child child;

  @Transactional
  public void parentMethod() {
    System.out.println("Parent");
    child.calledMethod();
  }
}

 

@Component
public class Child {
  @Transactional(propagation = ?) // <- 여기에 하나씩 넣어보세요.
  public void calledMethod() {
    System.out.println("Child");
  }
}

 

 

 

 

 

 

Isolation (격리 수준)

 

조회시점에 다른 트랜잭션들과 얼만큼 격리하여 얼마나 정확한 데이터 목록을 얻을지 결정한다.

 

고립도와 성능의 Trade-off 를 조절

READ UNCOMMITTED

다른 트랜잭션에서 커밋되지 않은 내용도 참조할 수 있다

READ COMMITTED - 현업 사용

다른 트랜잭션에서 커밋되 내용만 참조할 수 있다.

REPETABLE READ - 현업 사용

트랜잭션에 진입하기 이전에 커밋된 내용만 참조할 수 있다.

SERIALIZABLE

트랜잭션에 진입하면 락을 걸어 다른 트랜잭션이 접근하지 못하게 한다. (성능이 매우 떨어짐)

rollbackFor

@Transactional 은 기본적으로 Unchecked Exception, Error 만을 rollback 해줍니다.

그렇기 때문에 모든 예외에 대해서 rollback을 진행하고 싶을 경우(rollbackFor = Exception.class) 를 붙여야 합니다.

 

 

🤔 Exception 구분

Checked Exception : 예상된 에러로 해당 쓰레드내에서 회복이 가능한 예외

Unchecked Exception, Error : 예상치 못한 에러로 회복이 불가능한 예외

✋ 따라서, 근본적으로 HTTP API는 잘못된 요청에서 회복할 수 없다

클라이언트는 백엔드 API의 예외로부터 회복할 수 없다. 예외 발생 시 request의 라이프 사이클은 400, 404, 500 등 응답을 반환하고 끝이 난다. 클라이언트가 이 request를 회복 시킬 수는 없다. 다만 새로운 요청을 보낼 뿐이다. 클라이언트는 아무것도 할 수 없고 백엔드는 회복할 수 없다. 현재 프로그램의 흐름 내에서 회복할 수 있을때만 checked exception을 사용해야한다.