Tech Interview

[Backend] Spring Data JPA에서 새로운 Entity인지 판단하는 방법은 무엇일까요?

Yeom's 2025. 4. 3. 12:35
728x90
반응형
@Override
public boolean isNew(T entity) {

    if(versionAttribute.isEmpty()
          || versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {
        return super.isNew(entity);
    }

    BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);

    return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);
}

 

새로운 Entity인지 여부는 JpaEntityInformation의 isNew(T entity) 에 의해 판단됩니다. 다른 설정이 없으면 JpaEntityInformation의 구현체 중 JpaMetamodelEntityInformation 클래스가 동작합니다. 

@Version 이 사용된 필드가 없거나 @Version이 사용된 필드가 primitive 타입이면 AbstractEntityInformation의 isNew()를 호출합니다. @Version이 사용된 필드가 wrapper class이면 null 여부를 확인합니다.

Wrapper Class?
Wrapper Class는 기본형(primitive type) 데이터를 객체로 감싸는 클래스입니다. Java에서는 기본형 타입이 객체가 아니가 때문에, 객체로 다뤄야 하는 경우(예: 컬렉션에서 사용) Wrapper Class를 활용합니다.

 

public boolean isNew(T entity){
	Id id = getId(entity);
    Class<ID> idType = getIdType();
    
    if(!idType.isPrimitive()){
    	return id == null;
    }
    
    if(id instanceof Number){
    	return ((Number) id).longValue() == 0L;
    }
    
    throw new IllegalArgumentException(String.format("Unsupported primitive id type %s", idType));
}

 

@Version이 사용된 필드가 없어서 AbstractEntityInformation 클래스가 동작하면 @Id 어노테이션을 사용한 필드를 확인해서 primitive 타입이 아니라면 null 여부, Number의 하위 타입이면 0인지 여부를 확인합니다. @GeneratedValue 어노테이션으로 키 생성 전략을 사용하면 데이터베이스에 저장될 때 id가 할당됩니다. 따라서 데이터베이스에 저장되기 전에 메모리에서 생성된 객체는 id가 비어있기 때문에 isNew() 는 true가 되어 새로운 entity로 판단합니다.

 

직접 ID를 할당하는 경우에는 어떻게 동작하나요?

 

키 생성 전략을 사용하지 않고 직접 ID를 할당하는 경우 새로운 entity로 간주되지 않습니다. 이 때는 엔티티에서 Persistable<T> 인터페이스를 구현해서 JpaMetamodelEntityInformation 클래스가 아닌 JpaPersistableEntityInformation의 isNew() 가 동작하도록 해야합니다.

 

public class JpaPersistableEntityInformation<T extends Persistable<ID, ID>
		extends JpaMetamodelEntityInformation<T, ID> {
    
    public JpaPersistableEntityInformation(Class<T> domainClass, Metadmodel metamodel,
    		PersistenceUnitUtil persistenceUnitUtil){
        super(domainClass, metamodel, persistenceUnitUtil);
    }
    
    @Override
    public boolean isNew(T entity){
    	return entity.isNew();
    }
    
    @Nullable
    @Override
    public ID getId(T entity){
    	return entity.getId();
	}
}

 

 

새로운 Entity인지 판단하는 게 왜 중요할까요?

@Override
@Transactional
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);
	}
}

 

SimpleJpaRepository의 save() 메서드에서 isNew() 를 사용하여 persist를 수행할지 merge를 수행할 지 결정합니다. 만약 ID를 직접 지정해주는 경우에는 신규 entity라고 판단하지 않기 때문에 merge를 수행합니다. 이때 해당 entity는 신규임에도 불구하고 DB를 조회하기 때문에 비효율적입니다. 따라서, 새로운 entity인지 판단하는 것은 중요한 부분입니다.

728x90
반응형