기존 포스팅이 있지만 한번 더 작성해보았다.
[JPA] Spring Data JPA에서 새로운 Entity 판단하는 방법
[JPA] Spring Data JPA에서 새로운 Entity 판단하는 방법
Spring Data JPA에서 새로운 Entity를 저장할 때 public interface SaveTestRepository extends JpaRepository {} save @Transactional @Override public S save(S entity) { Assert.notNull(entity, "Entity must not be null."); if (entityInformation.isNew(e
devhooney.tistory.com
save()를 썼는데 insert가 안 돼요! update 된 것 같아요!
이거 왜 이런 걸까요?
Spring Data JPA를 쓰다 보면, 엔티티를 save() 했는데 INSERT가 아니라 UPDATE 되는 상황을 마주칠 수 있다.
그럴 땐 이렇게 질문이 들 수 있다.
“Spring Data JPA는 어떻게 새로운 엔티티인지 판단하는 거지?”
이번 포스팅에서는 그 기준과 해결 방법을 정리해보려 한다.
✅ 기본 규칙: @Id가 null이면 새로운 Entity
Spring Data JPA는 내부적으로 JPA의 EntityManager를 사용해 persist() 또는 merge()를 호출한다.
👉 동작 방식:
- @Id == null → persist() → INSERT
- @Id != null → merge() → UPDATE
즉, 엔티티의 ID 값이 null이면 새로운 객체(persist) 로 간주하고,
ID 값이 있으면 기존 객체(merge) 로 간주해서 update를 시도한다.
📌 예제
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
User u = new User();
u.setName("홍길동");
userRepository.save(u); // id가 null → INSERT
❗ 문제가 생기는 상황
예를 들어, ID가 자동 생성이 아닌 비즈니스 식별자일 경우엔 어떻게 될까?
@Entity
public class Product {
@Id
private String skuCode; // 비즈니스 키
private String name;
}
이 경우 skuCode가 존재해도, 이게 새로운 건지 기존 건지 판단할 방법이 없다.
왜냐하면 null이 아니니까 Spring Data JPA는 무조건 merge(update) 를 시도한다.
그래서 save()를 호출했는데도 INSERT가 안 되고, UPDATE가 발생하는 상황이 생기게 된다.
✅ 해결책: Persistable<T> 인터페이스 사용하기
이런 상황에서는 Spring Data JPA가 엔티티를 저장할 때
"이 객체는 새로운 것이야" 라고 명확히 알려줄 필요가 있다.
그때 사용하는 게 바로 org.springframework.data.domain.Persistable<T> 인터페이스이다.
🧩 예제
@Entity
public class Product implements Persistable<String> {
@Id
private String skuCode;
private String name;
@Transient
private boolean isNew = true;
@Override
public String getId() {
return skuCode;
}
@Override
public boolean isNew() {
return isNew;
}
@PostLoad
@PostPersist
public void markNotNew() {
this.isNew = false;
}
}
✔️ 핵심 포인트
- isNew()가 true면 → persist() → INSERT
- false면 → merge() → UPDATE
- @PostLoad, @PostPersist를 통해 영속화되면 자동으로 isNew = false로 바꿈
🔍 save() 내부 동작이 궁금하다면?
Spring Data JPA의 SimpleJpaRepository는 내부에서 이렇게 판단한다.
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
여기서 entityInformation.isNew()가 바로 위에서 설명한 isNew()이다.
🧪 테스트 코드 예시
@Test
void insertOrUpdateTest() {
Product p = new Product("ABC123", "신상 티셔츠");
productRepository.save(p); // isNew=true → INSERT
// 불러오고 다시 저장
Product loaded = productRepository.findById("ABC123").get();
productRepository.save(loaded); // isNew=false → UPDATE
}
'개발 > Java & Kotlin' 카테고리의 다른 글
[Spring] OSIV(Open Session In View) 옵션 (67) | 2025.06.30 |
---|---|
[Spring] Spring 프로젝트에서 레이어드 아키텍처 제대로 이해하기 (83) | 2025.06.23 |
[Gradle] Gradle을 알아보자! (78) | 2025.05.16 |
[Spring] 트랜잭션 롤백하는 예외 (76) | 2025.05.12 |
[Java] Null Object Pattern 공부 (29) | 2025.05.04 |