Hibernate와 함께 Spring Data JPA를 사용하면 Hibernate의 추가 기능도 사용할 수 있다.
@DynamicUpdte
는 그러한 기능 중 하나이다.
@DynamicUpdate
는 JPA Entity에 사용하는 어노테이션인데, 실제 값이 변경된 컬럼ㅁ만으로 update 쿼리를 만드는 기능이다.
Spring Data JPA를 사용해서 개발을 하다보면 수정 부분에서 변경되지 않은 컬럼도 update 쿼리에 포함하는데 큰 영향이 없어보이지만 쿼리 수가 많아질수록 차이가 발생한다.
Comment
@Entity
class Comment(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String body;
private Int likeCount;
private LocalDateTime createTime;
)
CommentRepository
interface CommentRepository : JpaRepository<Comment, Long> { }
Test
@Test
@Transactional
@Rollback(false)
public void update 결과 로그() {
Comment comment = commentRepository.findByIdOrNull(1)
?: throw EntityNotFoundException()
comment.likeCount = comment.likeCount + 1
}
실행결과
Hibernate: select comment0_.id as id1_1_0_, comment0_.article_id as article_5_1_0_, comment0_.body as body2_1_0_, comment0_.created_at as created_3_1_0_, comment0_.like_count as like_cou4_1_0_, article1_.id as id1_0_1_, article1_.body as body2_0_1_ from comment comment0_ left outer join article article1_ on comment0_.article_id=article1_.id where comment0_.id=?
Hibernate: update comment set article_id=?, body=?, created_at=?, like_count=? where id=?
실행 결과를 보면 likeCount의 값만 변경을 했음에도 불구하고, set 절 안에 body와 createdAt도 새로 변경값을 넣어주고 있는것을 알 수 있다.
자 이제 Comment에 @DynamicUpdate를 추가해서 다시 실행해보자.
Comment
@Entity
@DynamicUpdate
class Comment(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String body;
private Int likeCount;
private LocalDateTime createTime;
)
실행 결과
Hibernate: select comment0_.id as id1_1_0_, comment0_.article_id as article_5_1_0_, comment0_.body as body2_1_0_, comment0_.created_at as created_3_1_0_, comment0_.like_count as like_cou4_1_0_, article1_.id as id1_0_1_, article1_.body as body2_0_1_ from comment comment0_ left outer join article article1_ on comment0_.article_id=article1_.id where comment0_.id=?
Hibernate: update comment set like_count=? where id=?
update 쿼리의 set부분에 실제로 변경한 like_count만 설정이 추가되었음을 알 수 있다.
@DynamicUpdate
는 변경된 컬럼만 찾아서 업데이트를 진행한다.
언제 사용해야 좋을까?
공식 문서에는 '하나의 테이블에 정말 많은 수의 컬럼이 있는데, 몇몇개의 컬럼만 자주 업데이트 하는 경우에 사용하라'고 되어있다.
아니면 @Version
을 사용하지 않는 Optimistic Locking의 경우에 사용하라고 되어있다.
(Version을 사용하지 않고, 모든 필드를 Optimistic locking의 조건으로 걸게되면 어떤게 dirty 필드인지 체크해서 where조건을 만들 필요가 있기 때문)
출처
https://www.baeldung.com/spring-data-jpa-dynamicupdate
https://velog.io/@freddiey/JPA%EC%9D%98-DynamicUpdate
https://hyune-c.tistory.com/entry/DynamicUpdate-%ED%99%9C%EC%9A%A9%EA%B8%B0