spring data jpa 분석(새로운 엔티티 구별하는 방법)

Mina Park·2022년 10월 16일
0
  • save() 메소드의 구현부
	@Transactional
	@Override
	public <S extends T> S save(S entity) {

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

		if (entityInformation.isNew(entity)) {
			em.persist(entity);
			return entity;
		} else {
			return em.merge(entity);
		}
	}
  • save() 메소드의 작동 방식
    • 새로운 엔티티인 경우 persist(저장)
    • 새로운 엔티티가 아닌 경우 merge(병합)
  • 그렇다면 새로운 엔티티 여부를 어떻게 판단할까?

📌 새로운 엔티티를 판단하는 기본 전략

  • 식별자가 객체인 경우, null로 판단
  • 식별자가 자바 기본타입인 경우, 0으로 판단
  • 필요시 Persistable 인터페이스를 구현해서 직접 판단 로직을 정의할 수도 있음

[참고] JPA 식별자 생성 전략이 @GeneratedValue 인 경우

  • 기본적으로 flush하는 시점에 jpa가 식별자를 만들어줌
  • 따라서 save() 호출 시점에는 식별자가 없으므로 새로운 엔티티로 인식하여 정상 동작
  • 하지만 @Id만 사용하고 식별자를 직접 할당하는 경우에는 이미 식별자 값이 있는 상태로 save()를 호출 -> 당연히 jpa는 새로운 엔티티가 아니라고 판단하여 merge() 호출
    • merge()의 경우, 기본적으로 해당 엔티티가 이미 db에 존재함을 가정하므로, 우선 select 쿼리를 날려서 값을 확인하고 db에 값이 없을 경우 그제서야 새로운 엔티티로 인지 -> 매우 비효율적 프로세스
    • 이런 경우, Persistable 기능을 사용하여 새로운 엔티티 판단 로직을 직접 구현하는 것이 효율적
    • 참고로 등록시간(@CreatedDate)을 조합하여 사용하면 편리하게 판단 가능
      • 등록시간 값이 없는 경우 새로운 엔티티로 판단
  • Persistable 인터페이스
package org.springframework.data.domain;
public interface Persistable<ID> {
ID getId();
boolean isNew();
}
  • 엔티티에 Persistable 구현
@Entity
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item implements Persistable<String> {

//    @Id @GeneratedValue
//    private Long id;

    @Id
    private String id;

    @CreatedDate
    private LocalDateTime createdDate;

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

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

    //isNew 판단을 위한 로직을 직접 작성
    @Override
    public boolean isNew() {
        return createdDate == null;
    }

}

0개의 댓글