문제 설명
JPA를 사용하여 스케줄을 업데이트하는 메서드에서 다음과 같은 코드가 있었습니다.
public ScheduleUpdateResponse update(final ScheduleUpdateRequest request, final Long scheduleId) {
final Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new ScheduleApplicationException(SCHEDULE_NOT_FOUND));
schedule.update(request.title(), request.title());
return ScheduleUpdateResponse.from(schedule);
}
이 코드는 scheduleId로 엔티티를 조회한 후, 해당 엔티티의 필드를 업데이트하려고 합니다. 그러나 데이터베이스에 변화가 반영되지 않고, 확인해 본 결과 SELECT 쿼리만 실행되고 있었습니다.
원인
이 문제의 주요 원인은 @Transactional 어노테이션을 사용하지 않아 JPA의 변경 감지(Change Detection) 기능이 제대로 작동하지 않았기 때문입니다. JPA는 영속성 컨텍스트에 존재하는 엔티티의 상태를 관리하며, 엔티티의 상태가 변경되면 이를 감지하여 데이터베이스에 반영합니다. 하지만 영속성 컨텍스트가 없는 경우, JPA는 해당 엔티티의 변경을 감지하지 못합니다.
해결 방법
이 문제를 해결하기 위한 두 가지 방법이 있습니다.
@Transactional 사용
@Transactional을 통해 Entity를 영속화시키고 JPA의 변경감지를 이용하는 방법이다.
@Transactional
public ScheduleUpdateResponse update(final ScheduleUpdateRequest request, final Long scheduleId) {
final Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new ScheduleApplicationException(SCHEDULE_NOT_FOUND));
schedule.update(request.title(), request.title());
return ScheduleUpdateResponse.from(schedule);
}
이렇게 하면 schedule.update() 메서드에서 엔티티의 상태가 변경될 때, JPA는 이 변경을 감지하여 트랜잭션이 커밋될 때 자동으로 데이터베이스에 반영합니다.
save() 메서드 다시 호출
두 번째 방법은 엔티티를 수정한 후 scheduleRepository.save(schedule)를 호출하여 명시적으로 변경 사항을 저장하는 것입니다.
public ScheduleUpdateResponse update(final ScheduleUpdateRequest request, final Long scheduleId) {
final Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new ScheduleApplicationException(SCHEDULE_NOT_FOUND));
schedule.update(request.title(), request.title());
scheduleRepository.save(schedule); // 변경된 엔티티를 저장
return ScheduleUpdateResponse.from(schedule)
이 방법은 트랜잭션을 사용하지 않더라도 변경된 엔티티를 명시적으로 데이터베이스에 저장하기 때문에, 데이터가 제대로 업데이트됩니다.
2가지 방법 모두 update쿼리가 생성된다.
결론
업데이트를 수행할 때 save 메서드를 사용하는 것은 코드의 흐름에서 의문을 일으킬 수 있을 거라고 생각합니다. "왜 업데이트 시에 다시 저장해야 할까?"라는 의문이 생길 수 있기 때문입니다. 따라서 JPA의 변경 감지 기능을 활용하여 엔티티의 상태를 자동으로 추적하고, 데이터베이스에 반영하는 방식이 더 자연스럽고 효율적이라고 생각합니다. 이를 통해 코드의 가독성이 높아질 거 같습니다!
'WEB' 카테고리의 다른 글
회원가입 후 JWT 응답 제거 (1) | 2024.10.30 |
---|---|
3N+1 문제와 프록시 강제 초기화 해결 (0) | 2024.10.23 |
날씨 API 사용과 리팩토링 (0) | 2024.10.15 |
소프트 딜리트란? (1) | 2024.09.27 |
Spring Data JPA로 된 코드를 JDBC로 다시 짜보기 (1) | 2024.09.25 |
MDC를 이용한 로깅 도입기 (0) | 2024.09.23 |
@SpringBootTest vs @Mock (0) | 2024.09.12 |
스프링부트의 Tomcat과 Thread Pool (0) | 2024.09.10 |