[JPA] @LastModifiedDate 일부 필드 제외하기

NCOOKIE·2023년 9월 21일
0
post-thumbnail

들어가며

현재 개발하고 있는 프로젝트에서 Review라는 테이블이 있는데, 리뷰의 생성 및 마지막 수정시간을 기록하기 위해 @CreatedDate@LastModifiedDate 어노테이션을 사용하는 필드를 만들었다.

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {

    @CreatedDate
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;

}

리뷰의 좋아요/싫어요를 업데이트하는 요청을 받게 되면 관련 테이블 작업을 하고나서 Review 테이블의 likeCnt와 dislikeCnt 필드의 값을 수정한다. 이 때 테이블이 업데이트 되면서 @LastModifiedDate 필드도 같이 갱신되었다.

그러나 리뷰의 마지막 수정시간은 제목, 본문, 평점과 같은 정보들이 수정되고 좋아요/싫어요 카운트는 여기에서 제외되길 원했다. 그래서 방법들을 찾아보았다.

해결방법

테이블 분리하기

아예 likeCnt와 dislikeCnt 필드를 다른 테이블로 분리하여 사용하는 방법이 있다. 하지만 데이터 수정, 조회 시 소요되는 리소스가 더 많다고 판단되어 후보에서 제외했다.

@PreUpdate 사용하여 @LastModifiedDate 대체하기

JPA에는 해당 엔티티의 데이터가 업데이트되기 직전에 실행되는 메서드에 사용하는 @PreUpdate라는 어노테이션이 있다.

@Entity
public class Review extends BaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long reviewId;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private UserAccount userAccount;

    @ManyToOne
    @JoinColumn(name = "contents_id")
    private Contents contents;
    
    @Setter
    private String title;

    @Setter
    private String content;

    @Setter
    private float score;
    
    private Date created;			// 생성시간
  	private Date modified;			// 마지막 수정시간

    @Transient
    private Review previousState;

    @PostLoad 
    public void setPreviousState() {
      previousState = new Review();
      // copy fields
    }

    @PreUpdate
    public void preUpdate() {
       if (isModified()) {
          modified = new Date();
       }
    }   

    private boolean isModified() {
      boolean modified = false;

      if (!title.equals(previousState.title) || !content.equals(previousState.content) || ...) {
          modified = true;
      }

      //check other fields

      return modified;
    }
}

위와 같이 이전 상태를 저장했다가 엔티티가 업데이트 되면 값을 비교하여 특정 필드가 수정될 때에만 date를 갱신할 수 있다.

이러한 방법은 원하는 특정 필드의 값이 수정될 때에만 마지막 수정 시간을 갱신할 수 있다는 장점이 있지만, 이전 상태를 가지고 있어야 하고 관련된 필드가 늘어날 때마다 isModified() 메소드를 수정해주어야 하는 등의 번거로움이 있다.

JPQL로 Query 작성하여 필드 업데이트하기

@LastModifiedDate 어노테이션은 JPA의 내부 이벤트 처리 메커니즘에 의해 관리된다. 이 어노테이션은 엔티티가 JPA에 의해 관리되는 경우에만 자동으로 업데이트되며, 직접 JPQL(Java Persistence Query Language)을 사용하여 업데이트 쿼리를 실행할 때는 작동하지 않는다. 이러한 점을 이용하여 특정 필드 값을 업데이트해도 @LastModifiedDate 필드가 갱신되지 않도록 할 수 있다.

public interface ReviewRepository extends JpaRepository<Review, Long> {
    Page<Review> findAllByContents(Contents contents, Pageable pageable);
    
	// ...

    @Modifying
    @Query("UPDATE Review SET likeCnt = :likeCnt WHERE reviewId = :reviewId")
    void updateLikeCount(@Param("reviewId") Long reviewId, @Param("likeCnt") int likeCnt);

    @Modifying
    @Query("UPDATE Review SET dislikeCnt = :dislikeCnt WHERE reviewId = :reviewId")
    void updateDislikeCount(@Param("reviewId") Long reviewId, @Param("dislikeCnt") int dislikeCnt);
}

// like, dislike count 갱신
reviewRepository.updateLikeCount(review.getReviewId(), reviewLikeService.getLikeCount(review));
reviewRepository.updateDislikeCount(review.getReviewId(), reviewLikeService.getDislikeCount(review));

출처

profile
일단 해보자

0개의 댓글