inblog logo
|
devleekangho
    프로젝트이야기

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

    KangHo Lee's avatar
    KangHo Lee
    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
    Contents
    느낀 점

    devleekangho

    RSS·Powered by Inblog