문제 상황
AccessService에서 출입 인증 시 실패 로그가 저장되지 않는 문제가 발생 !
출입 인증 메서드(processFaceAccess 또는 processQrAccess) 내에서 예외 발생 시,
실패 로그 저장을 위해 LogService.saveFailLog가 호출됨
→ 그러나 예외로 인해 부모 트랜잭션 전체가 롤백되면서 FailLog 저장도 함께 롤백
→ AccessLog는 정상 흐름에서 예외 없이 저장되어 DB에 남지만, FailLog는 저장되지 않음
출입 인증 처리 기대 플로우
1. 클라이언트가 출입 요청을 보냄
2. AccessService의 processFaceAccess/processQeAccess가 요청 처리 시작
3. 출입 조건 충족 여부에 따라 AccessLog 저장
4. 예외 발생 시 LogService.saveFailLog로 실패 로그 저장
5. 결과에 따라 출입 성공 또는 실패 응답 반환
문제 발생 지점
예외 발생 시 실패 로그 저장을 위해 LogService.saveFailLog를 호출하지만,
해당 메서드가 부모 트랜잭션 내에 포함되어 있어 트랜잭션 전체가 롤백되면서 실패 로그가 DB에 남지 않음
문제 해결
LogService의 saveFailLog를 독립적인 트랜잭션으로 분리
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveFailLog(...) {
failLogRepository.saveAndFlush(...); // 즉시 반영
}
- Propagation.REQUIRES_NEW ≫ 별도의 트랜잭션(T2)을 생성
- 부모 트랜잭션(T1)이 예외로 롤백되어도, T2는 독립적으로 커밋됨!
- saveAndFlush()를 사용해 즉시 DB에 반영되도록 처리
트랜잭션 전파 (Propagation)
하나의 트랜잭션 내에서 다른 트랜잭션이 호출될 때 기존 트랜잭션을 어떻게 처리할지 결정하는 속성
자주 사용하는 옵션 3가지
옵션 | 설명 |
REQUIRED (기본값) | 현재 트랜잭션이 있으면 참여, 없으면 새로 생성 |
REQUIRED_NEW | 항상 새 트랜잭션 생성, 기존 트랜잭션은 일시 중단 |
NESTED | 현재 트랜잭션 안에 중첩 트랜잭션 생성 |
트랜잭션 내에서 예외 발생 시에도 로그 등을 보존하기 위해서는
트랜잭션 전파 옵션 REQUIRES_NEW를 활용하여 독립적인 커밋 흐름을 구성할 것!
+ saveAndFlush로 커밋 타이밍을 명확하게 하기
'트러블슈팅' 카테고리의 다른 글
CustomException 처리 중 DB 저장 오류로 인한 500 에러 해결 (0) | 2025.04.29 |
---|---|
Spring Security 로그인 예외 처리 - 401 대신 500에러 발생 문제 해결 (0) | 2025.04.29 |