1 minute read

트랜잭션은 데이터의 일관성을 보장하는 매우 중요한 기능이지만, 그 자체가 만능은 아닙니다.

트랜잭션이 만능이 아니란 사실에대해 한 가지 상황을 가정해 보겠습니다.

시나리오

서비스코드 1 과 서비스 코드 2 가 존재하며, 서비스코드 1 이 사용될때 서비스코드 2를 호출하면서 서비스코드2는 에러를 throw한다.

첫번째 Checked Exception이 발생하는 경우의 코드를 정의 합니다.

public class CustomException extends Exception{
    public CustomException(String message){
        super(message);
    }
}

이후 두개의 서비스코드를 정의

@Service
public class ServiceCode {

    @Autowired
    private SomeRepository repository;

    @Transactional
    public void firstMethod() throws CustomException{
        repository.save(new SomeEntity("name"));
        secondMethod();
    }

    private void secondMethod() throws CustomException{
        throw new CustomException("Check Exception 발생했습니다.");
    }
}

테스트코드 작성

@SpringBootTest
public class transactionTest {

    @Autowired
    private ServiceCode serviceCode;

    @Autowired
    private SomeRepository repository;

    @Test
    public void test() throws CustomException{
        // checked Exception이 발생
        Assertions.assertThrows(CustomException.class, ()->serviceCode.firstMethod());
        Optional<SomeEntity> byId = repository.findById(1L);
        Assertions.assertEquals(1,byId.get().getId());
    }
}

실행하기 이전의 제가 생각하는 트랜잭션 실행 예상으로

  • firstMethod를 호출함으로써 트랜잭션 단에서 save메서드가 실행되고 secondMethod가 다음으로 호출되면서 예외를 발생시킵니다.

예상대로라면 에러가 발생했을시 트랜잭션이 선언된 코드는 원자성을 보장해야함으로 firstMethod에서 실행한 save메소드는 객체를 저장하지 않아야 하죠

코드를 실행하면

트랜잭션 실행결과

하지만, 실행결과는 다음과 같이 객체는 exception이 발생하더라도 roll-back처리가 되지않음을 알 수 있습니다.

그에대한 원인으로 @Transactional의 처리 속성을 이해해야합니다.

스프링의 @Transactional 은 기본적으로 Unchecked Exception(런타임 예외) 만 트랜잭션의 롤백 대상이 됩니다. Checked Exception이 발생했을 때는 트랜잭션이 자동으로 롤백되지 않죠.

그렇다면 Uchecked Exception 과 Checked Exception 의 차이는 뭘까요?

Untitled

Untitled

@Transactional은 Checked Exception예외 상황에서만 데이터를 보장합니다.

Checked Exception은 주로 외부의 시스템과 연동할 경우나, 파일 I/O, 데이터베이스 SQl과 같이 개발자가 제어할 수 없는 영역에서 발생하는 오류를 말합니다.

UnChekced Exception은 컴파일러가 체크하지않는 예외, 즉 개발자의 실수로 발생하는 예외로 발생합니다. 예를 들어, null값에 접근할 때 발생하는 NullPointException이 대표적인 예시죠

이처럼 트랜잭션을 올바르게 사용하기 위해선 예외처리 방식, 트랜잭션 범위 등 여러가지를 고려해야합니다.

그 외에도 트랜잭션의 범위 설정()이나 격리 수준 설정(Isolation)도 중요한 요소이기에 다음 개념들도 학습하면 트랜잭션 성능에대해 좀더 자세히 알 수 있을거 같습니다.