끼리끼리 프로젝트를 하면서
여느때와 마찬가지로, 값을 수정해주고, save()해주고를 반복하고 있었다.
그러던 중, 더티체킹과 save()의 기능에 대해 헷갈리게 되었고, 계속 이에 대해 생각하게 되었다.
분명 값을 업데이트를 하면 더티체킹으로 인해 영속성 컨텍스트에 있는 값이 업데이트 되고 트랜잭션이 커밋되면 DB에 반영이 되는 것으로 알고 있었다.
하지만 그러면 update를 해주면 (엔티티의 값을 바꾸어주면) 따로 save()를 해주지 않아도 되는 것인가 헷갈리기 시작했다.
이에 대해 알아보던중 아주 좋은 질문을 발견했고, 결론은 더티체킹은 save를 대체하는 것이 아니라 update를 대체해주는 것이라고 이해가 되었다.
그래서 아래의 코드에서 @Transactional
이 적용되어 있다는 가정하에, findPost.updatePost(post);
을 해주게 되면 트랜잭션이 끝나는 때에 알아서 DB에 바뀐 값이 적용이 된다. 그러면 따로 postRepository.save(findPost);
을 해주지 않아도 되는 것이다.
// @Transactional 클래스 위에 존재=================================
// 게시글 수정
public SaveResPost updatePost(Post post, Long id, List<Long> imageIdList) {
// update 를 해줘야 함. 그런데 member 의 내용은 바뀌지 않음. 수정은 인증된 사용자만 할 수 있으므로.
Optional<Post> optPost = postRepository.findById(id);
if(optPost.isEmpty()) {
throw new RuntimeException("해당 포스트를 찾을 수 없습니다.");
}
Post findPost = optPost.get();
// findPost.updatePost(post,id);
findPost.updatePost(post);
Post savedPost = postRepository.save(findPost);
// ====== 이미지 수정하기
// 이미지를 수정하지 않는 경우,
if(imageIdList == null || imageIdList.isEmpty()) {
List<String> existedImageUrlList = imageService.findImageUrlsByPostId(savedPost.getId());
// 원래 포스트에 이미지가 존재하지 않은 경우
if(existedImageUrlList == null || existedImageUrlList.isEmpty()) {
SaveResPost saveResPost = SaveResPost.of(savedPost);
return saveResPost;
}
// 원래 포스트에 이미지가 존재하지만 수정하지 않는 경우
SaveResPost saveResPost = SaveResPost.ofWithImage(savedPost, existedImageUrlList);
return saveResPost;
}
// 게시글을 수정할때 이미지를 수정하는 경우,
List<String> savedImageUrlList = imageService.savePost(savedPost, imageIdList);
SaveResPost saveResPost = SaveResPost.ofWithImage(savedPost, savedImageUrlList);
return saveResPost;
}
이러한 더티체킹이 적용되는 경우는 두가지이다.
1. save()로 값이 DB에 저장되는 경우
2. 이미 DB에 저장된 값을 꺼내와서 바꾸는 경우이다.
더티체킹에 대해 더 공부하고 고민해본후 더 객체지향적으로 좋은 코드를 짜보도록 하자!!
참고
https://github.com/jojoldu/freelec-springboot2-webservice/issues/47
https://velog.io/@hyunho058/Spring-Data-JPA-%EB%8D%94%ED%8B%B0-%EC%B2%B4%ED%82%B9Dirty-Checking