Service 에서 공통으로 사용하는 조회 함수를 ServiceUtil 클래스로 분리 중 생긴 이슈
Service 에서 공통으로 사용하는 읽기 작업들을 ServiceUtil 로 분리
그럼 ServiceUtil는 @Transactional(readOnly = true) 가 될 것이다.
@Transactional 은 트랜잭션 전파 레벨이 Default 로 REQUIRED 이다.
REQUIRED 는, 부모(함수가 호출된 곳) 트랜잭션이 존재할 시, 해당 트랜잭션을 사용하는 옵션이다.
문제점 : 그럼 ServiceUtil 이 readOnly 여도, ServiceUtil 를 호출하는 곳이 readOnly 가 아니라면, ServiceUtil 에서도 쓰기 작업이 가능해져버린다.
해결 방안 ?
그럼 트랜잭션 전파 레벨을 REQUIRES_NEW 로 해서 매번 새로운 트랜잭션을 시작하게 하면 되지 않을까?
해당 해결 방안의 문제점: 트랜잭션이 너무 많아 데드 락 문제가 발생할 수 있다. 1 개의 트랜잭션은 1 개의 DB 커넥션을 사용하는데, 많은 요청이 동시에 들어오면 DB 커넥션 풀이 고갈되어 모든 커넥션들이 새로운 커넥션을 대기하는 데드 락이 발생할 수 있다.
그러므로, REQUIRES_NEW 는 사용을 지양해야 할 것 같다.
그런데..
공통 사용하는 조회 메서드를 ServiceUtil 로 분리하지 않는다고 해도, readOnly 를 사용하지 않는 Service 에서는 이미 조회 메서드가 있다.
조회 메서드를 readOnly 가 아닌 트랜잭션이 호출할 것이므로, 조회 메서드는 readOnly 가 아닌 트랜잭션을 공유해 사용하게 된다.
그럼 어차피 해당 조회 메서드를 사용하는 메서드는 readOnly 가 아닌 트랜잭션을 사용한다는 의미이므로, readOnly 를 사용하는 ServiceUtil 로 분리해도 똑같은 것이다.
그러므로
ServiceUtil 을 사용하는 곳을 고려하지 말고, ServiceUtil 에 readOnly 한 Transactional 을 적용하고, 읽기 작업만 수행하도록 하자.
클래스는 자신이 어디에 사용될지 고려해선 안된다.
그러므로, 특별한 문제(트랜잭션과 같은)가 없다면, 클래스는 자신과 자신이 사용하는 클래스에 대해서만 신경쓰면 된다.
Description
패키지 구조, 클래스명 정리
Changes
ServiceUtil 정의 - ReadOnly 작업만 수행하는 공통 메서드를 가짐
AuthenticationConfig 를 일반 Component 클래스로 변경 후, WebConfig 에서 사용하도록 -> 인터셉터 등록 순서를 보장하기 위함
Logging 에 사용되는 RequestIdInterceptor 를 등록하는 LoggingConfig 생성 후, WebConfig 에서 사용하도록 -> 인터셉터 등록 순서를 보장하기 위함
+ 자잘한 클래스명, 패키지 이동
Additional context