기타/문제 해결

@Transactional 과 @Async 사용 시 주의점

펭귄힝 2024. 5. 30. 10:09

 

이번 게시글에서는 동시성 문제를 테스트하기 위해 테스트 코드를 작성하던 중 발생했던 @Transactional 문제를 기록하려 한다.

 

 

 

테스트 코드다. @Transactional 이 붙어있고 리뷰를 저장하고 reviewService.deleteReview() 메서드를 호출해서 리뷰를 삭제하는 간단한 코드다.

 

 

 

 

 

 

reviewService.deleteReview() 내부 코드인데 (@Async 어노테이션을 주목하자) validateReview() 메서드를 호출해서 해당 리뷰가 존재하는 리뷰인지 확인한다.

 

 

 

 

 

 

그리고 validateReview() 내에서는 리포지토리를 통해 실제 DB(or 1차 캐시) 에 접근한다.

 

 

 

 

 

테스트 코드를 실행해보면 위와 같은 오류가 발생하게 된다. 리포지토리를 통해 리뷰를 조회했는데 찾을 수 없다는 오류다. 이거 때문에 몇 시간을 삽질한건지 모르겠다.

 

일단 일반적인 로직대로라면 @Transactional 어노테이션이 붙어있기 때문에 리뷰를 저장하는 로직 부분에서 영속성 컨텍스트의 1차 캐시에 내용을 저장하게 된다. 그리고 validateReview() 부분에서 영속성 컨텍스트를 통해서 1차 캐시의 값을 조회하게 될텐데, 호출하는 메서드의 @Async 가 붙은 경우는 이렇게 동작하지 않는다.

 

왜냐하면 @Async 어노테이션이 붙은 메서드를 호출하게되면 새로운 쓰레드를 만들고 이를 비동기로 처리하기 때문이다. 그리고 새로 만들어진 쓰레드는 당연히 트랜잭션 전파가 되지 않는다.테스트 코드의 @Transactional 이 붙어있기 때문에 실제 DB 에는 값이 반영되지 않았을테고 이는 당연히 오류로 이어질 수 밖에 없었던 것이다.

 

 

 

 

 

 

 

 

참고 자료