일단 Transactional option 이 뭔지 잘 모르겠어서 찾아봤다
더보기
@Transactional(
propagation = Propagation.REQUIRED, # 전파 옵션 (이미 transaction 이 있을때 어떻게 할지)
isolation = Isolation.DEFAULT, # 격리 수준: 기본은 DB 설정 따르기
readOnly = false, # 조회전용 (dirty checking 안할게염)
rollbackFor = Exception.class, # 언제 rollback 을 할건지
timeout = 30 # transaction 을 얼마간 잡고있을건지 -> 30초 넘으면 롤백
)
이번에 쓰는건 propagation 이라 해당부분만 추가
| REQUIRED | 기존 트랜잭션 있으면 참여, 없으면 생성 -> 기본 propagation 옵션 설정 안 하면 얘임 |
| REQUIRES_NEW | 기존 트랜잭션 있으면 잠깐 중단하고 새 트랜잭션 생성 -> 원래 비즈니스 로직에서 exception 던져져도 log 는 그대로 기록 |
| SUPPORTS | 트랜잭션이 실행중이면 참여함 -> exception 뜨면 rollback 되고, exception 안 뜨면 저장 되고 transaction 이 없다면 그냥 transaction 없이 실행 |
| NOT_SUPPORTED | 트랜잭션 실행중이면 중단 |
| MANDATORY | 반드시 트랜잭션 필요 없다면 exception -> 무조건 트랜잭션 안에서만 실행되어야함 |
| NEVER | mandatory 와 반대 : 트랜잭션 있으면 예외 |
| NESTED | 부모 트랜잭션 내부 savePoint 생성 -> 일부 롤백 가능 |
일단 commit 이 되는것과 관계없이 모든 요청에 log 를 남겨야하는거니까 Requires_new 를 사용하기로 결정!!
더보기
EventListener 랑 같이 쓰는 경우가 있다고 함
applicationEventPublisher.publishEvent(event);
# 이 때 after commit 말고 after completion 을 쓰면 성공, 실패 상관 없이 실행되므로
# 과제에 event listener 를 썼다면 얘를 썼을듯
# 이후에 commit 이 완료되었다 하면 성공 결과 저장용으로 after commit,
# exception 이 발생했다고 하면 after rollback 으로 저장했을 것 같다
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(Event e){
ManagerLogService.saveInitial( );
}
문제
manager save log 를 남길 때 처음에 Manager Service 에서 아래처럼 둘 다 작성하려고 했음
@Transactional
public ManagerSaveResponse saveManager
(AuthUser authUser, long todoId, ManagerSaveRequest managerSaveRequest) {
# 요청이 들어왔을 때 바로 log 를 생성
saveInitialLog(authUser.getId(), todoId, managerSaveRequest.getManagerUserId());
# 생략
}
# level 11 : 매니저 등록 요청 시 로그 기록
# transaction option 을 활용해서 save manager 와 logging 이 개별로 이루어질 수 있도록 하기
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveInitialLog(Long loginUserId, Long todoId, Long managerId){
ManagerLog log = new ManagerLog(loginUserId, todoId, managerId);
managerLogRepository.save(log);
}
근데 실패하는 경우만 로그가 안 남는다 . . . 이유를 모르겠어서 더 고민해보니까
같은 클래스의 내부 호출을 하면 @Transactional 이 무시됨 (들었던 거 같은데 까먹었다. . . )
저장이 안 되는 흐름은 아래와 같다
Spring transaction 은 proxy 기반인데 동일 클래스면 proxy 를 안 거침
-> 그냥 일반 메서드가 호출
-> 한 transaction 안에 묶임
-> REQUIRES_NEW 안 됨
-> exception 나면 저장 아무것도 안 됨
뭐 이런 .... 로직인듯 하다
일단 class 를 분리해줌
@Service
@RequiredArgsConstructor
public class ManagerLogService {
private final ManagerLogRepository managerLogRepository;
# level 11 : 매니저 등록 요청 시 로그 기록
# transaction option 을 활용해서 save manager 와 logging 이 개별로 이루어질 수 있도록 하기
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Long saveInitialLog(Long loginUserId, Long todoId, Long managerId){
ManagerLog log = new ManagerLog(loginUserId, todoId, managerId);
ManagerLog savedLog = managerLogRepository.save(log);
return savedLog.getId();
}
# 해당 요청이 성공했는지 실패했는지,,, 결과값도 저장
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveResultLog(Long logId, boolean status, String message){
ManagerLog log = managerLogRepository.findById(logId).orElseThrow();
log.addResult(status, message);
}
}
@Transactional
public ManagerSaveResponse saveManager(
AuthUser authUser, long todoId, ManagerSaveRequest managerSaveRequest) {
# 요청이 들어왔을 때 바로 log 를 생성
Long logId = managerLogService.saveInitialLog(
authUser.getId(), todoId, managerSaveRequest.getManagerUserId());
# try catch 로 감싸서 error 발생하면 잡아서 log 에 추가해주기
try{
# 비즈니스 로직 생략
# 성공은 return 전에 기록
managerLogService.saveResultLog(logId, true, "매니저 등록에 성공했습니다.");
return new ManagerSaveResponse(
savedManagerUser.getId(),
new UserResponse(managerUser.getId(), managerUser.getEmail())
);
}catch (Exception e){
# 실패는 잡아서 개별 메시지도 넣어주기
managerLogService.saveResultLog(logId, false, e.getMessage());
throw e;
}
}

값이 정상적으로 저장



야호