Search

[7/17] JPA에서 update 쿼리를 날릴 때

Created time
2024/07/16 17:32
Tags
SpringBoot
프로젝트

문제: 변경하지 않은 컬럼까지 update 쿼리가 발생한다.

update를 한 필드는 최대 3개인데, 실제 실행되는 쿼리를 살펴보면 entity의 전 영역을 수정하고 있다.
@Override public Account modify(Account account, AccountModify req) { // 1. password가 변경되었다면, 새로운 password를 암호화 if (!passwordService.isValidPassword(account.getPassword(), req.getPassword())) { req.encryptPassword(passwordService.encryptPassword(req.getPassword())); } // 2. domain 객체를 업데이트 account.changeProfile(req); // 3. update 쿼리 실행 accountRepository.findById(account.getId()) .orElseThrow(() -> new IllegalArgumentException("올바르지 않은 접근입니다.")) .update(account); // 4. 업데이트된 도메인 객체 리턴 return account; } public class AccountEntity { ... public void update(Account account) { this.password = account.getPassword(); this.profile = account.getProfile(); this.name = account.getName(); } }
Java
복사
2024-07-17T02:40:42.201+09:00 DEBUG 31411 --- [nio-8080-exec-3] org.hibernate.SQL : update account set campus=?, email=?, is_campus_certificated=?, name=?, password=?, profile=? where id=?
Plain Text
복사

@DynamicUpdate

import org.hibernate.annotations.DynamicUpdate; @Entity @Getter @NoArgsConstructor @DynamicUpdate <-- Here! @Table(name = "account") public class AccountEntity extends BaseEntity
Java
복사
만약 변경된 컬럼만 update하고 싶다면, @DynamicUpdate 어노테이션을 엔티티 위에 추가하면 된다.
이는 Hibernate에서 지원하는 기능이며, 이에 따라 Hibernate는 @DynamicUpdate 어노테이션이 적용된 엔티티의 상태를 추적하게 된다. 구체적으로, 엔티티 필드를 변경할 때 현재 상태와 변경된 이후의 상태를 계속해서 비교한다.
만약 적용되지 않는다면, 이런 비교 단계 없이 바로 update 쿼리를 발생시키므로, 이미 생성되어 캐시된 쿼리를 발생시킬 수 있다. 작게나마, 혹은 수정이 잦은 엔티티의 경우 꽤 크게 성능 오버헤드가 유의미하게 작용한다.
따라서 위와 같이 6-7개정도 되는 컬럼을 업데이트하는 경우 굳이 이러한 기능을 사용할 필요가 없다.

@DynamicUpdate를 사용해야 할 때

많은 컬럼을 가진 엔티티일 때 사용한다. 구체적으로 20개 이상쯤 되면 사용하게 된다. 그렇지 않으면 서버 → DB로 갈 때 네트워크 리소스와 각 인스턴스의 CPU를 크게 낭비하게 된다.
컬럼 수준의 Lock을 지원하는 DB일 때 사용한다.
마찬가지로, 컬럼 수준의 버저닝을 지원할 때 발생한다.
동시성 이슈가 발생할 때 사용한다. 하지만 @DynamicUpdate 보다는 분산 락 등을 사용하는 것이 낫다.