[ 김영한 스프링 데이터 JPA #9 ] 새로운 엔티티를 구별하는 방법

김수호·2024년 6월 6일
0
post-thumbnail

스프링 데이터 JPA 가 제공하는 공통 인터페이스의 구현체(SimpleJpaRepository)에서 save() 메서드를 확인해보자.

@Transactional
@Override
public <S extends T> S save(S entity) {

	Assert.notNull(entity, "Entity must not be null");

	if (entityInformation.isNew(entity)) {
		entityManager.persist(entity);
		return entity;
	} else {
		return entityManager.merge(entity);
	}
}

내부 로직을 보면, 엔티티가 새로운 엔티티인지 아닌지를 판단하는 isNew() 의 결과에 따라, persist() 를 할지, merge() 를 할지 결정하고 있다.

참고로 isNew() 에서 새로운 엔티티를 판단하는 기본 전략은 다음과 같다.

  • 식별자가 객체일 때는 null 로 판단한다.
  • 식별자가 자바 기본 타입일 때는 0 으로 판단한다.

 

🤔 그러면 만약 엔티티의 식별자에 @GenerateValue 를 쓰지 못하는 상황(=직접 ID를 생성해서 등록해야 하는 경우)에서 save() 를 호출하는 경우는 어떻게 처리될까?

이 경우라면, 일반적으로 save() 가 호출되기 전에 이미 식별자 값이 지정되어 호출될 것이다. 따라서 이때는 merge 로 처리된다. 즉, merge 의 동작 매커니즘에 따라, 우선 해당 식별자가 DB에 존재하는지 먼저 조회(select)를 하게 되는 것이다. 따라서, 이는 매우 비효율적이다.

이런 경우는 어떻게 처리하면 좋을까?

다음과 같이, Persistable 인터페이스를 구현해서, 새로운 엔티티를 판단하는 전략을 변경할 수 있다.

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(AuditingEntityListener.class)
public class Item implements Persistable<String> {

    @Id
    private String id;

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    public Item(String id) {
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public boolean isNew() {
        return createdDate == null;
    }
}

참고로 새로운 엔티티인지 판단의 기준으로 등록시간( @CreatedDate )을 조합해서 사용하면 편리하게 확인할 수 있다. ( @CreatedDate 에 값이 없으면 새로운 엔티티로 판단하는 것이다. )

 

✔️ 참고

  • Persistable 인터페이스

강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 김영한 강사님께 있습니다.

profile
현실에서 한 발자국

0개의 댓글