• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

트랜잭션 범위 질문

23.01.08 19:34 작성 조회수 1.44k

0

- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
- 먼저 유사한 질문이 있었는지 검색해보세요.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.

 

안녕하세요,

TaskletStep - 개념 및 API 소개 수강하면서 궁금한 점이 있어 여쭤보고자 합니다.

 

TaskletStep의 경우 트랜잭션 경계 내에서 수행되며, 따로 트랜잭션 처리를 하지 않아도 SpringBatch에서 알아서 트랜잭션 설정을 해주는 것으로 이해를 하였는데요.

만약, TaskletStep 내에 커스텀하게 만든 Tasklet 속에서 Service(@Transactional 어노테이션이 붙은)를 호출하게 된다면, 이 서비스 로직은 TaskletStep의 트랜잭션 내에 트랜잭션이 또 생겨서 독립적으로(?) 움직이는 것인지 궁금합니다.

 

답변 기다리겠습니다.

감사합니다.

답변 1

답변을 작성해보세요.

1

이부분은 스프링 배치의 트랜잭션 흐름을 조금 상세하게 알아야 하는데요..

기본적으로 스프링 배치에서는 read, process, write 의 프로세스를 하나의 트랜잭션으로 감싸고 있습니다.

이 트랜잭션은 Tasklet 안에서 시작하고 종료하게 됩니다.

여기서 만약 Tasklet 에 @Transactional 을 선언했다면 스프링 배치의 기본 트랜잭션 외부에 별도의 트랜잭션이 위치하게 됩니다.

스프링 배치에서 생성한 트랜잭션은 트랜잭션을 시작하고 종료할 때까지 어플리케이션 단에서 하나의 Lock 으로 동기화 하고 있습니다. 즉 트랜잭션 시작시 Lock 을 획득하고 트랜잭션 종료시 Lock 을 해제하는 식으로 되어 있습니다. 그리고 이 조건은 트랜잭션이 커밋하는 시점과 맞물려 있습니다.

스프링에서 트랜잭션의 전파는 기본적으로 이전의 트랜잭션을 계속 물려 받도록 되어 있습니다.
즉 Tasklet 에서 선언한 @Transactional 트랜잭션을 스프링 배치의 기본 트랜잭션이 물려 받아 실행이 되는데 문제는 스프링 배치의 기본 트랜잭션이 Lock 을 획득하고 해제하는 시점이 @Transactional 을 통한 외부의 트랜잭션이 시작하고 해제하는 시점과 틀려서 일종의 데드락이 발생한다는 점입니다.

즉 @Transactional 의 트랜잭션이 시작할 때 Lock 을 획득하고 Tasklet 이 실행되다가 스프링 배치의 기본 트랜잭션이 동일하게 Lock 을 획득할려고 하는데 @Transactional 에서 획득한 Lock 이 아직 커밋 시점이 오지 않아서 해제가 되지 않게 되고 그래서 스프링 배치의 기본 트랜잭션도 Lock 획득하기 위해 계속 대기해야 하는 상황이 발생하게 됩니다.

이런 상황을 해결하기 위해서는 스프링 배치에서 이전의 @Transactional 트랜잭션을 물려 받는 것이 아니라 새롭게 트랜잭션을 생성하는 전파 방식을 선언한면 됩니다.

예를 들어 PROPAGATION_REQUIRES_NEW 전파 방식을 별도로 새롭게 정의하면 됩니다.

하지만 이 역시도 이전의 트랜잭션과 독립적으로 움직이기 때문에 데이터 일관성이 깨지는 문제가 발생할 수 있습니다.

그래서 스프링 배치에서는 @Transactional 와 같은 외부 트랜잭션을 선언하는 것을 원칙적으로 금지하고 있다고 보시면 됩니다.