728x90
반응형
발생 상황
- SpringBoot 3, JPA
- 통계 프로젝트 진행 중 특정 일자에 저장, 그리고 특정 일자를 조회 하기에 인덱스를 사용하기 위해서 복합키를 사용하기로 함.
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class DataDate implements Serializable {
private LocalDate startDate;
private LocalDate endDate;
private int weekNumber;
}
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode
public class Statistics {
@EmbeddedId
private DataDate dataDate;
@Embedded
private EventCount eventCount;
@Embedded
private OsCount osCount;
}
문제 상황
Hibernate: select s1_0.end_date,s1_0.start_date,s1_0.week_number ~~~~))
Hibernate: insert into ~~~
- 엔티티를 저장하기 전에 select 쿼리가 날라감.
- 만 건의 데이터를 저장하기 위해서는 만 건의 select를 실행하기 때문에 오버헤드가 있다고 판단
해결
- JpaRepository의 구현체인 SimpleRepository의 save() 메서드를 확인
private final JpaEntityInformation<T, ?> entityInformation;
@Transactional
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null");
if (this.entityInformation.isNew(entity)) {
this.entityManager.persist(entity);
return entity;
} else {
return this.entityManager.merge(entity);
}
}
- isNew 메서드를 통해 엔티티가 새로운 엔티티라면 persist, 아니라면 merge 하는 방식
- isNew 메서드는 엔티티의 식별자가 없는 경우 true, 있는 경우 false를 반환
- 식별자가 없는 경우란 @GeneratedValue를 설정한 경우
- 따라서 isNew 메서드를 엔티티에 재정의하면 된다 생각함
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode
public class Statistics implements Persistable<DataDate> {
@EmbeddedId
private DataDate dataDate;
@Embedded
private EventCount eventCount;
@Embedded
private OsCount osCount;
@Transient // 테이블의 컬럼과 매핑시키지 않음
@Builder.Default // Builder의 기본 값
private boolean isNew = true;
@PrePersist // 영속 상태의 엔티티를 이용하여 데이터 업데이트를 수행하기 이전에 실행
@PostLoad // 엔티티를 로딩한 후에 호출
void markNotNew() {
this.isNew = false;
}
@Override
public DataDate getId() {
return this.dataDate;
}
@Override
public boolean isNew() {
return this.isNew;
}
}
결과
Hibernate: insert into ====
- insert 전에 select 쿼리가 발생하지 않음
느낀점
- 대부분의 프로젝트에서 @GeneratedValue를 사용하기 때문에 insert 이전에 select 쿼리가 발생한다는 사실도, SimpleJpaRepository의 save 메서드에서 키 값을 통해 persist 혹은 merge를 한다는 사실을 알지 못했음
- JPA를 사용해서 개발 중에는 항상 SHOW-SQL 옵션을 켜서 예상치 못한 쿼리가 날라가는지 확인해야 한다는 것을 느낌
728x90
반응형