이 글은 인프런 김영한님의 Spring 강의를 바탕으로 개인적인 정리를 위해 작성한 글입니다.
이 글은 JPA의 변경 감지와 병합에 대한 이해가 필요합니다.
2024.08.05 - [Java Category/JPA] - [JPA] 병합(Merge)과 변경 감지(Dirty Checking)
save() 메서드의 구조
org.springframework.data.jpa.repository.support.SimpleJpaRepository
- 새로운 엔티티면 저장( persist )
- 새로운 엔티티가 아니면 병합( merge )
save()가 새로운 엔티티를 판단하는 기본 전략
- 식별자가 객체일 때 null 로 판단
- 식별자가 자바 기본 타입일 때 0 으로 판단
- Persistable 인터페이스를 구현해서 판단 로직 변경 가능
식별자가 객체일 때 null로 판단
엔티티의 기본키가 자바의 기본 타입이 아니라 String 등이고, 식별자(기본키)가 null 이면 영속성 컨텍스트에서 관리하지 않는 새로운 객체라고 판단한다.
이 때, 주의를 해야하는 점이 있다.
데이터베이스에서 자동으로 식별자를 지정해주는 전략이 아니라 애플리케이션에서 자체적으로 식별자를 지정해주는 전략이라면 새로운 엔티티가 생성될 때, persist가 아니라 merge가 작동하게 된다.
따라서 영속성 컨텍스트는 데이터베이스에서 데이터를 조회하게 되고, DB에 데이터가 없다는 것을 뒤 늦게 알고 그제서야 새로운 객체로 판단하게 된다.
JPA 식별자 생성 전략이 @Id 만 사용해서 직접 할당이면 이미 식별자 값이 있는 상태로 save() 를 호출한다.
따라서 이 경우 merge() 가 호출된다. merge() 는 우선 DB를 호출해서 값 을 확인하고, DB에 값이 없으면 새로운 엔티티로 인지하므로 매우 비효율적이다.
따라서 Persistable 를 사용해서 새로운 엔티티 확인 여부를 직접 구현하게는 효과적이다.
식별자가 자바 기본 타입일 때 0으로 판단
int 나 long 등 자바의 기본 타입이라면 초기화를 하지 않았다면 기본적으로 0으로 세팅되어있다.
따라서 엔티티의 식별자가 0이면 영속성 컨텍스트에서 관리하지 않는 새로운 객체라고 판단한다.
@Entity
public class Item {
@Id @GeneratedValue
private Long id;
}
식별자 생성 전략이 @GenerateValue 면 save() 호출 시점에 식별자가 없으므로 새로운 엔티티 로 인식해서 정상 동작
Persistable 인터페이스를 구현
등록시간( @CreatedDate )을 조합해서 사용하면 이 필드로 새로운 엔티티 여부를 편리하게 확인할 수 있다.
(@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
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; //생성 시간이 null이면 새로운 객체로 판단하도록 유도
}
}
'Java Category > JPA' 카테고리의 다른 글
[Query DSL] Query DSL 초기 세팅 (0) | 2024.08.17 |
---|---|
[Spring Data JPA] Projections 과 Native Query (0) | 2024.08.16 |
[Spring Data JPA] 확장 기능 (0) | 2024.08.14 |
[Spring Data JPA] 쿼리 메서드 기능 (0) | 2024.08.13 |
[Spring Data JPA] Spring Data JPA (0) | 2024.08.12 |