최근에 겪었던 이슈를 해결하면서 배운점을 적어봅니다
트랜잭션의 범위를 적당하게 잡아야하는 이유는 뭘까?
만약 시간이 오래걸리는 외부API호출이나 I/O작업을 트랜잭션 범위 내에서 수행하게 된다면 어떻게 될까?
DB에 롱 트랜잭션이 발생하게 되어 아웃풋이 예상치 못한 동작이 발생할 수 있다.
예시를 들면 다음같은 로직의 메소드는 한 트랜잭션이 매우 길어질 수 있다.
// 시작
1. findBy~
2. deleteBy~
3. 1번 결과물에 대해 시간이 많이 걸리는 로직 수행
// 종료
그렇다면 이를 해결 할 수 있는 방법은?
- 진입점 나누기
해당 로직을 굳이 한 진입점에서 수행할 필요가 없다면 두개 이상의 API, 진입점으로 나누어 진행하면 된다. - 다른 트랜잭션에서 수행하게 하기
진입점이 반드시 한곳이어야 하는 등 1번을 수행하기 어려운 상황이라면 트랜잭션을 나눌 수 있다.
스프링의 @Transactional 에는 propagation 옵션이 존재한다.
디폴트는 REQUIRED이고, 여기서 필요한것은 REQUIRED_NEW 이다.
디폴트인 REQUIRED 옵션은 기존 트랜잭션 진행 중에 트랜잭셔널 어노테이션이 있는 메소드를 호출했을 때, 기존의 트랜잭션을 같이 사용하게 한다. 즉, 다른 메소드에서 에러가 발생 시 기존 메소드 진행상황까지 롤백되게 되는 것이다.
REQUIRED_NEW 옵션은 기존에 부모 트랜잭션이 존재하더라도 기존 트랜잭션을 중단하고 새 트랜잭션을 시작하여 부모 트랜잭션과 별개로 커밋할 수 있도록 한다.
나눌 수 있는 로직은 위 옵션을 활용하여 트랜잭션을 나누어 진행한다.
만약 많은 수의 데이터를 처리해야한다면, 반복문을 활용하여 트랜잭션을 나누어 커밋하는 방법을 사용할 수 있다.
baeldung 사이트의 설명과 공식 독스의 설명+그림을 참고해서 보면 이해가 쉽다
1. Transaction Propagation and Isolation in Spring @Transactional
2. Transaction Propagation
그리고...
로직을 나눈다고 같은 클래스 안에서 새 메소드를 만들고 거기에 @Transactional을 붙이면 어떻게 될까??
다음 포스팅으론 트랜잭션 사용 시 가장 자주하는 실수를 다뤄보고자 한다.
'트러블슈팅' 카테고리의 다른 글
트랜잭션 분리 시 주의점 (0) | 2024.02.11 |
---|