-
0. JpaMetamodelEntityInformation.isNew(T entity)
-
1. JpaEntityInformation
-
1 - 1. 엔티티 식별
-
1 - 2. 엔티티 메타데이터 접근
-
1 - 3. 엔티티 관리
-
2. JpaMetamodelEntityInformation
-
2 - 1. `@Version` 필드 확인
-
2 - 2. `@Id` 필드 확인
-
2 - 3. `@GeneratedValue` 사용 시
-
3. 직접 ID를 할당하는 경우에는 어떻게 동작하는가?
-
3 - 1. 예시 - Persistable<String> 을 구현한 Item 엔티티
-
4. 새로운 Entity인지 판단하는게 왜 중요할까?
-
References
0. JpaMetamodelEntityInformation.isNew(T entity)
@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);
}
새로운 Entitiy인지 여부는 JpaEntityInformation의 isNew(T entity)에 의해 판단된다. 다른 설정이 없으면 JpaEntityInformation의 구현체 중 JpaMetamodelEntityInformation 클래스가 동작한다. `@Version`이 사용된 필드가 없거나 `@Version`이 사용된 필드가 primitive 타입이면 AbstractEntityInformation의 isNew()를 호출한다. `@Version`이 사용된 필드가 wrapper class이면 null 여부를 확인한다.
1. JpaEntityInformation
JpaEntityInformation은 Spring Data JPA에서 엔티티의 메타데이터를 분석하고 관리하는 인터페이스이다.
다음과 같은 주요 기능을 제공한다.
1 - 1. 엔티티 식별
새로운 엔티티인지 여부를 판단하는 isNew()메서드를 제공한다.
1 - 2. 엔티티 메타데이터 접근
엔티티의 ID 타입, 속성 정보 등을 제공한다.
1 - 3. 엔티티 관리
SimpleJpaRepository와 같은 구현체에서 엔티티를 효율적으로 관리하는데 사용된다.
2. JpaMetamodelEntityInformation
JpaEntityInformation의 주요 구현체로는 JpaMetamodelEntityInformation이 있다.
이 구현체는 다음과 같은 방식으로 새로운 엔티티를 판단한다.
2 - 1. `@Version` 필드 확인
AbstractEntityInformation.isNew(T entity)
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` 필드가 없거나 기본 타입이면 부모 클래스의 isNew() 메서드를 사용한다.(AbstractEntityInformation)
`@Version` 필드가 있고 래퍼 클래스라면, 해당 필드의 값이 null인지 확인한다.
2 - 2. `@Id` 필드 확인
`@Id` 필드가 기본 타입이 아니면, null인지 확인한다.
`@Id` 필드가 숫자 타입이면, 값이 0인지 확인한다.
2 - 3. `@GeneratedValue` 사용 시
`@GeneratedValue` 어노테이션을 사용하면, 데이터베이스에서 저장될 때 ID가 할당되므로,
메모리에 생성된 객체는 ID가 없어 새로운 엔티티로 판단된다.
3. 직접 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, Metamodel 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();
}
}
3 - 1. 예시 - Persistable<String> 을 구현한 Item 엔티티
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Item implements Persistable<String> {
@Id
private String id;
@CreatedDate
private LocalDateTime createdDate;
public Item(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public boolean isNew() {
return createdDate == null;
}
}
직접 ID를 생성하는 경우 위와 같이 Persistable<T> 인터페이스를 구현하고,
엔티티의 특성에 맞는 isNew() 로직을 직접 작성해야 한다.
4. 새로운 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);
}
}
새로운 엔티티인지 판단하는 것은 JPA의 save 메서드 동작에 중요한 영향을 미친다. SimpleJpaRepository의 save() 메서드에서 isNew()를 사용하여 persist를 수행할지 merge를 수행할지 결정한다. 새로운 엔티티로 판단되면 persist()를 호출하여 엔티티를 데이터베이스에 삽입하고, 기존 엔티티로 판단되면 merge()를 호출하여 엔티티를 업데이트 한다. merge()가 호출시 엔티티가 데이터베이스에 존재하는지 확인하기 위해 SELECT 쿼리가 실행된다. 이는 불필요 연산이다. 그리고, 새로운 엔티티를 기존 엔티티로 오인하여 merget()를 호출하면, 의도치 않게 기존 데이터를 수정하거나 덮어쓸 수 있다.
References
https://www.maeil-mail.kr/question/27
https://hyewoncc.github.io/jpa-is-new/
https://velog.io/@hj_/Spring-Data-JPA-Spring-Data-JPA-%EB%B6%84%EC%84%9D
'백엔드 면접 질문' 카테고리의 다른 글
일급 컬렉션이 무엇인가요? (1) | 2024.11.29 |
---|---|
자바에서 Checked Exception과 Unchecked Exception에 대해서 설명해주세요. (0) | 2024.11.28 |
JPA의 N + 1 문제에 대해서 설명해주세요 (2) | 2024.11.27 |
Entity Manager에 대해 설명해주세요. (0) | 2024.11.26 |
JPA의 ddl-auto 옵션은 각각 어떤 동작을 하고 어떤 상황에서 사용해야 할까요? (0) | 2024.11.25 |
0. JpaMetamodelEntityInformation.isNew(T entity)
@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);
}
새로운 Entitiy인지 여부는 JpaEntityInformation의 isNew(T entity)에 의해 판단된다. 다른 설정이 없으면 JpaEntityInformation의 구현체 중 JpaMetamodelEntityInformation 클래스가 동작한다. `@Version`이 사용된 필드가 없거나 `@Version`이 사용된 필드가 primitive 타입이면 AbstractEntityInformation의 isNew()를 호출한다. `@Version`이 사용된 필드가 wrapper class이면 null 여부를 확인한다.
1. JpaEntityInformation
JpaEntityInformation은 Spring Data JPA에서 엔티티의 메타데이터를 분석하고 관리하는 인터페이스이다.
다음과 같은 주요 기능을 제공한다.
1 - 1. 엔티티 식별
새로운 엔티티인지 여부를 판단하는 isNew()메서드를 제공한다.
1 - 2. 엔티티 메타데이터 접근
엔티티의 ID 타입, 속성 정보 등을 제공한다.
1 - 3. 엔티티 관리
SimpleJpaRepository와 같은 구현체에서 엔티티를 효율적으로 관리하는데 사용된다.
2. JpaMetamodelEntityInformation
JpaEntityInformation의 주요 구현체로는 JpaMetamodelEntityInformation이 있다.
이 구현체는 다음과 같은 방식으로 새로운 엔티티를 판단한다.
2 - 1. `@Version` 필드 확인
AbstractEntityInformation.isNew(T entity)
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` 필드가 없거나 기본 타입이면 부모 클래스의 isNew() 메서드를 사용한다.(AbstractEntityInformation)
`@Version` 필드가 있고 래퍼 클래스라면, 해당 필드의 값이 null인지 확인한다.
2 - 2. `@Id` 필드 확인
`@Id` 필드가 기본 타입이 아니면, null인지 확인한다.
`@Id` 필드가 숫자 타입이면, 값이 0인지 확인한다.
2 - 3. `@GeneratedValue` 사용 시
`@GeneratedValue` 어노테이션을 사용하면, 데이터베이스에서 저장될 때 ID가 할당되므로,
메모리에 생성된 객체는 ID가 없어 새로운 엔티티로 판단된다.
3. 직접 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, Metamodel 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();
}
}
3 - 1. 예시 - Persistable<String> 을 구현한 Item 엔티티
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Item implements Persistable<String> {
@Id
private String id;
@CreatedDate
private LocalDateTime createdDate;
public Item(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public boolean isNew() {
return createdDate == null;
}
}
직접 ID를 생성하는 경우 위와 같이 Persistable<T> 인터페이스를 구현하고,
엔티티의 특성에 맞는 isNew() 로직을 직접 작성해야 한다.
4. 새로운 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);
}
}
새로운 엔티티인지 판단하는 것은 JPA의 save 메서드 동작에 중요한 영향을 미친다. SimpleJpaRepository의 save() 메서드에서 isNew()를 사용하여 persist를 수행할지 merge를 수행할지 결정한다. 새로운 엔티티로 판단되면 persist()를 호출하여 엔티티를 데이터베이스에 삽입하고, 기존 엔티티로 판단되면 merge()를 호출하여 엔티티를 업데이트 한다. merge()가 호출시 엔티티가 데이터베이스에 존재하는지 확인하기 위해 SELECT 쿼리가 실행된다. 이는 불필요 연산이다. 그리고, 새로운 엔티티를 기존 엔티티로 오인하여 merget()를 호출하면, 의도치 않게 기존 데이터를 수정하거나 덮어쓸 수 있다.
References
https://www.maeil-mail.kr/question/27
https://hyewoncc.github.io/jpa-is-new/
https://velog.io/@hj_/Spring-Data-JPA-Spring-Data-JPA-%EB%B6%84%EC%84%9D
'백엔드 면접 질문' 카테고리의 다른 글
일급 컬렉션이 무엇인가요? (1) | 2024.11.29 |
---|---|
자바에서 Checked Exception과 Unchecked Exception에 대해서 설명해주세요. (0) | 2024.11.28 |
JPA의 N + 1 문제에 대해서 설명해주세요 (2) | 2024.11.27 |
Entity Manager에 대해 설명해주세요. (0) | 2024.11.26 |
JPA의 ddl-auto 옵션은 각각 어떤 동작을 하고 어떤 상황에서 사용해야 할까요? (0) | 2024.11.25 |