작성
·
54
·
수정됨
0
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예
[질문 내용]// 인증 번호 확인
@Transactional
public void confirmAuthenticationInfo(AuthenticationRequest.Confirm request){
MemberCertificationHistory history = findById... // 엔티티 조회
...
validateExpiration(history);
...
}
// 만료 일시 검증
@Transactional
private void validateExpiration(MemberCertificationHistory history){
if(history.isExpired()){
processExpiration(history); // 만료 처리 . 트랜잭션 분리
throw new ServerException("만료됨"...);
}
}
// 인증 정보 만료 처리
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void processExpiration(MemberCertificationHistory history){
history.getMemberCertificationInfo().processExpiration();
memberCertHisRepository.save(history); // 엔티티 저장
}
안녕하세요 위 코드에서 궁금한점이 있는데 내부호출에 관한 내용인지 질문드립니다.
간단하게 confirmAuthentication() , validateExpiration() , processExpiration() 3가지 메서드가 있는상황이구, 차례로 호출하며 validateExpiration()에서 throw를 던지는 상황입니다.
문제는
validateExpiration()를 내부에서 트랜잭션이 분리 처리(REQUIRES_NEW)되어 있는 processExpiration()를 타게되고, processExpiration()는 분리된 트랜잭션이니 .save()를 통해 저장이되고, 다시 validateExpiration()으로 돌아와 throw를 처리하게 되어 processExpiration()에서 저장된것은 롤백되지 않을것으로 예상하였습니다.
그런데 로그를보니 insert쿼리도 나가지 않고, 따로 롤백에 관한 내용도 찍히지 않았습니다.
따라서 내부호출이 된건가 생각을해보니 제가 아는 내부호출이라는 문제는
동일한 클래스에서 트랜잭션이 적용되지 않은 메서드에서 트랜잭션이 적용된 메서드 호출시 내부 호출이 발생하는걸로 알고있는데 위 예제에선 이미 최상위 메서드에서 트랜잭션이 적용되어 있는상태인데 따로 생성된 트랜잭션이 실행되지 않아서 혹시 이건 내부호출 문제가 맞는것인지, 아니면 다른 제가 간과한것이 있는지 궁금하여 질문드립니다 .
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
질문 주신 내용을 통해 나타난 문제는 “내부 호출” 문제와 연관이 있는 것으로 보입니다. JPA와 트랜잭션 관리의 특성상, 동일 클래스 내부에서의 트랜잭션 관리가 제대로 되지 않을 수 있습니다. 이를 이해하기 위해 트랜잭션과 AOP 프록시의 동작 방식을 이해하는 것이 중요합니다.
내부 호출 문제: @Transactional
메서드가 같은 클래스 내의 다른 메서드를 호출할 때 트랜잭션이 적용되지 않는 경우가 있습니다. 이는 Spring이 프록시를 사용하여 트랜잭션을 처리하기 때문입니다. 프록시를 통해서가 아닌, 직접 호출할 경우(메서드 내부에서 직접 호출), 트랜잭션 설정이 적용되지 않을 수 있습니다.
현재 상황 분석:
confirmAuthenticationInfo
메서드는 @Transactional
이 붙어 있고, 내부적으로 validateExpiration
을 호출합니다.validateExpiration
또한 @Transactional
이지만 같은 클래스 내에서 호출되므로, 트랜잭션이 원활히 작동하지 않을 수 있습니다. 이는 confirmAuthenticationInfo
메서드의 트랜잭션에 포함된 호출로 간주될 수 있습니다.processExpiration
는 REQUIRES_NEW
를 통해 별도의 트랜잭션을 생성하려고 시도합니다. 이 경우, 내부 호출이 아니고 AOP 프록시를 통할 수 있는 환경이어야 별도 트랜잭션이 적용됩니다.트랜잭션 전파로 인한 문제:
REQUIRES_NEW
전략은 새로운 트랜잭션을 강제로 생성하려고 합니다. 그러나 내부 호출의 문제로 인해 새로운 트랜잭션으로 인식되지 않을 수 있습니다.이와 같은 상황에서 해결 방법으로 다음을 고려할 수 있습니다:
분리된 Bean으로 메서드 배치: processExpiration
메서드를 별도의 Bean으로 분리하여 호출하면, AOP 프록시로 인해 트랜잭션 전파가 의도대로 작동할 수 있습니다.
메서드 호출 방식을 변경: @Transactional
이 적용된 메서드를 직접 호출하는 대신, 의존성 주입된 다른 bean에서 호출하도록 리팩토링합니다.
문제 이해에 도움이 될 추가적인 정보를 원하신다면, 비슷한 사례에 대한 설명 및 코드를 가이드하는 문서를 살펴보시길 추천드립니다:
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
음 그럼 내부 호출이라는 것은 상위 메서드에 트랜잭션이 설정되어 있는것과는 아무런 상관이 없고 무조건 동일 클래스내에 있는 메서드 호출시 발생하는걸로 이해했는데 맞을까요 ?ㅜㅜㅠ..