[이상형 월드컵 프로젝트 문제 해결] Comment 삭제 테스트 중 문제 - 영속성 컨텍스트 관련

KangHo Lee's avatar
Dec 30, 2024
[이상형 월드컵 프로젝트 문제 해결] Comment 삭제 테스트 중 문제 - 영속성 컨텍스트 관련
Contents
느낀 점
Comment
@NoArgsConstructor @Getter @Table(name = "comment_tb") @Entity public class Comment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(nullable = false) private String content; private String winnername; @CreationTimestamp @Column(nullable = false) private Timestamp createdAt; @ManyToOne(fetch = FetchType.LAZY) private User user; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) private Worldcup worldcup; @Column(nullable = false) private String nickname; }
CommentRepository
@RequiredArgsConstructor @Repository public class CommentRepository { private final EntityManager entityManager; public Comment findById(Integer id) { return entityManager.find(Comment.class, id); } public void saveComment(Comment comment) { entityManager.persist(comment); } public void deleteComment(Integer id) { entityManager.createQuery("DELETE FROM Comment c WHERE c.id = :id") .setParameter("id", id) .executeUpdate(); } }
CommentRepositoryTest.java
public void deleteComment_test() { // given User user = User.builder().id(1).build(); Worldcup worldcup = Worldcup.builder().id(1).build(); Comment comment = Comment.builder() .nickname("nickname") .content("content") .user(user) .worldcup(worldcup) .build(); commentRepository.saveComment(comment); Comment commentPS = commentRepository.findById(1); System.out.println("코멘트 아이디는 : " + commentPS.getId()); commentRepository.deleteComment(1); Comment deletedComment = commentRepository.findById(1); System.out.println("코멘트 아이디는 : " + deletedComment.getId()); }
  • 결과
    • 삭제된 코멘트의 id가 계속 존재
  1. saveComment 만 따로 테스트
  1. commentRepository 쿼리문 점검
  1. 코멘트 저장을 더미 데이터로 저장 (data.sql)
  1. 위의 여러 가지 방법을 동원했으나 결과는 변하지 않음
// application.properties 파일에 추가 # 2. 하이버네이트 spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true
  • hibernate 설정에서 쿼리문을 콘솔에 출력하도록 설정
@Test public void deleteComment_test() { // given User user = User.builder().id(1).build(); Worldcup worldcup = Worldcup.builder().id(1).build(); Comment comment = Comment.builder() .nickname("nickname") .content("content") .user(user) .worldcup(worldcup) .build(); commentRepository.saveComment(comment); System.out.println("<1. insert 쿼리 발동함>"); Comment commentPS = commentRepository.findById(1); System.out.println("<2. select 쿼리 발동?"); System.out.println("코멘트 아이디는 : " + commentPS.getId()); commentRepository.deleteComment(1); System.out.println("<3. delete 쿼리 실행>"); Comment deletedComment = commentRepository.findById(1); System.out.println("<4. 재조회 쿼리 실행?>"); System.out.println("코멘트 아이디는 : " + deletedComment.getId()); }
  • Lazy Loading을 고려하여 쿼리문 실행되는 시점을 파악하기 위해 System.out.println을 꼼꼼히 배치
Hibernate: insert into comment_tb (content, created_at, is_deleted, nickname, user_id, winnername, worldcup_id, id) values (?, ?, ?, ?, ?, ?, ?, default) <1. insert 쿼리 발동함> <2. select 쿼리 발동?> 코멘트 아이디는 : 1 Hibernate: delete from comment_tb c1_0 where c1_0.id=? <3. delete 쿼리 실행> <4. 재조회 쿼리 실행?> 코멘트 아이디는 : 1
  • select 쿼리가 실행되지 않음 → 엔티티 매니저가 관리하는 영속성 컨텍스트 캐싱 관련 문제임을 파악

수정된 테스트 코드

@Test public void deleteComment_test() { // given User user = User.builder().id(1).build(); Worldcup worldcup = Worldcup.builder().id(1).build(); Comment comment = Comment.builder() .nickname("nickname") .content("content") .user(user) .worldcup(worldcup) .build(); commentRepository.saveComment(comment); System.out.println("<1. insert 쿼리 발동함>"); Comment commentPS = commentRepository.findById(1); System.out.println("<2. select 쿼리 발동 안함 (캐싱됨)>"); System.out.println("코멘트 아이디는 : " + commentPS.getId()); commentRepository.deleteComment(1); System.out.println("<3. delete 쿼리 실행>"); entityManager.clear(); System.out.println("<4. 강제 clear 함 - db에 쿼리는 날라갔고, PC에 남아있는 찌거기 날려버리기>"); Comment deletedComment = commentRepository.findById(1); System.out.println("<5. 재조회 쿼리 실행>"); System.out.println("코멘트 아이디는 : " + deletedComment.getId()); }

콘솔 결과

Hibernate: insert into comment_tb (content, created_at, is_deleted, nickname, user_id, winnername, worldcup_id, id) values (?, ?, ?, ?, ?, ?, ?, default) <1. insert 쿼리 발동함> <2. select 쿼리 발동 안함 (캐싱됨)> 코멘트 아이디는 : 1 Hibernate: delete from comment_tb c1_0 where c1_0.id=? <3. delete 쿼리 실행> <4. 강제 clear 함 - db에 쿼리는 날라갔고, PC에 남아있는 찌거기 날려버리기> Hibernate: select c1_0.id, c1_0.content, c1_0.created_at, c1_0.is_deleted, c1_0.nickname, c1_0.user_id, c1_0.winnername, c1_0.worldcup_id from comment_tb c1_0 where c1_0.id=? <5. 재조회 쿼리 실행> Cannot invoke "com.metacoding.projectwc.comment.Comment.getId()" because "deletedComment" is null
  • 정상적으로 Comment가 삭제된 것을 확인

느낀 점

  • 머릿속으로 캐싱에 대해 이론을 알고 있었음에도 실제 코드에 적용하기 쉽지 않았습니다.
  • 꼼꼼한 로그 출력의 중요성을 느꼈습니다.
 
Share article

devleekangho