프로젝트/일정관리

[일정관리앱ver.2] updatedDate(updatedAt) 즉시 반영이 안되는 문제

yoney 2025. 2. 12. 20:00

[목차]


    💢문제 발생

    일정 crud 기능을 구현하면서 일정을 업데이트하고 결과를 조회해보면 updatedDate이 변경되지 않았다.

    그리고 나서 다시 update 요청을 하면 그제서야 updatedDate이 바뀌는 문제가 발생했다.

    처음에 update 요청을 보내자마자 updateDate이 즉시 반영되도록 구현을 시도했다.


     

    ✏️ 기존 코드 및 원인

    - ScheduleService.java

    @Transactional
        public ScheduleResponseDto updateSchedule(Long id, ScheduleRequestDto scheduleRequestDto) {
            Schedule schedule = scheduleRepository.findById(id)
                    .orElseThrow(() -> new BusinessException("id가 존재하지 않습니다.: " + id, HttpStatus.NOT_FOUND));
            schedule.updateSchedule(scheduleRequestDto.getTitle(),scheduleRequestDto.getContents());
            return new ScheduleResponseDto(schedule);
        }

     

    - ScheduleController.java

    @PatchMapping("/{id}")
        public ResponseEntity<ScheduleResponseDto> updateSchedule(@PathVariable Long id, @RequestBody ScheduleRequestDto scheduleRequestDto) {
            return new ResponseEntity<>(scheduleService.updateSchedule(id, scheduleRequestDto), HttpStatus.OK);
        }

     

     

    updatedDate가 즉시 반영되지 않고 두번째 get 요청 후 변경되는 문제의 원인은 JPA의 변경 감지가 트랜잭션 종료 후에 동작하기 때문이었다.

    @Transactional 어노테이션이 붙으면 트랜잭션이 끝날 때까지 변경된 엔티티를 모아두고 있다가 메서드가 종료되면 updateDate을 반영한다고 한다.


    ✏️ 해결 과정

    👉🏻 첫번째 시도

    변경된 값을 한 번 db에 저장하고 반환해주기 위해 service 클래스에서 save()를 사용해보았다.

    @Transactional
    public ScheduleResponseDto updateSchedule(Long id, ScheduleRequestDto scheduleRequestDto) {
        Schedule schedule = scheduleRepository.findById(id)
                .orElseThrow(() -> new BusinessException("id가 존재하지 않습니다.: " + id, HttpStatus.NOT_FOUND));
    
        schedule.updateSchedule(scheduleRequestDto.getTitle(), scheduleRequestDto.getContents());
    
        scheduleRepository.save(schedule);
    
        return new ScheduleResponseDto(schedule);
    }

     

    jpa가 schedule의 내용을 db에 반영한다.

    그런데 이 방법으로도 updateDate가 즉시 바뀌지 않았다.


    👉🏻 두번째 시도

    두번째 시도로 saveAndFlush()를 사용했다.

    @Transactional
        public ScheduleResponseDto updateSchedule(Long id, ScheduleUpdateRequestDto scheduleUpdateRequestDto) {
            Schedule schedule = scheduleRepository.findById(id)
                    .orElseThrow(() -> new BusinessException("id가 존재하지 않습니다.: " + id, HttpStatus.NOT_FOUND));
            schedule.updateSchedule(scheduleUpdateRequestDto.getTitle(), scheduleUpdateRequestDto.getContents());
            scheduleRepository.saveAndFlush(schedule);
            return new ScheduleResponseDto(schedule);
        }

    flush는 jpa에서 변경된 내용을 db에 즉시 반영하는 메서드이다. 즉시 변경 사항을 db에 반영하지만 트랜잭션을 유지할 수 있다.

    이렇게 하니까 해결이 됐다! 바로 updatedDate이 반영되었다.


    🔍 메서드 차이

    save랑 flush의 차이가 뭐길래 save로는 해결이 안됐는데 flush를 쓰니까 해결이 됐을까?

    찾아보니까 save도 트랜잭션 종료 시에 한번에 반영된다고 한다. 즉시 반영이 필요할 경우 saveAndFlush를 사용하면 되는데, 즉시 DB에 반영되기 때문에 flush가 자주 일어나면 성능이 저하될 수 있다.

    메서드 동작 방식 트랜잭션 유지 여부 updateDate 반영 시점
    save() 영속성 컨텍스트에 저장 후, 트랜잭션 종료 시 DB 반영 (Flush 지연) O 트랜잭션이 끝날 때 반영됨
    saveAndFlush() 영속성 컨텍스트에 저장 + 즉시 flush() 실행하여 DB 반영 O 호출 즉시 반영됨

     


    📌 결론

    db에 즉시 반영이 필요하면 saveAndFlush를 사용한다.

    하지만 flush가 많이 일어나면 성능 저하가 있기 때문에 필요할 때만 사용하는 것이 좋다!