작심삼일

[매일메일] 27. Spring Data JPA에서 새로운 Entity인지 판단하는 방법은 무엇일까요? 본문

스터디/AI 개발자가 공부하는 백엔드

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

yun_s 2025. 4. 30. 18:21
728x90
반응형

이 게시판에서는 매일메일이라는 시스템을 이용해 백엔드를 공부해보고자하는 AI 개발자가 정리해보고자 합니다.

Python이랑 비교하여 이해하기 쉽도록 합니다.

https://www.maeil-mail.kr/question/27

 

매일메일 - 기술 면접 질문 구독 서비스

기술 면접 질문을 매일매일 메일로 보내드릴게요!

www.maeil-mail.kr


용어 및 질문 이해하기 

Spring Data JPA에서 새로운 Entity인지 어떻게 판단할까?

 

나는 Spring Data JPA라는 것부터 몰라서 이것부터 찾아봤다.

간단하게 말하면 Spring Data JPA라는 것은 다음과 같다.

복잡한 SQL 없이, 자바 코드로 DB에 데이터를 저장하고 꺼낼 수 있게 해주는 Spring의 기술

 

Spring Data JPA는 이런 일을 할 수 있다고 한다.

  • 자바 클래스(Entity)를 DB 테이블로 매핑
  • save(), findById() 같은 메서드로 자동 SQL 처리
  • Repository 인터페이스만 만들면 복잡한 코드 없이 DB 연동 가능

그래서 이게 뭔소린가 싶은데, pytorch에 비교해보면 이렇게 생각할 수 있다.

PyTorch의 model.save()처럼 Spring Data JPA는 userRepository.save()객체를 DB에 저장해준다.

 

그렇다면 Entity라는건 뭘까?

Entity는 데이터베이스(DB) 테이블과 매핑되는 자바 클래스다.

 

Pytorch에 비교하면 Entity는 nn.Module 과 비슷하다고 생각할 수 있다.

nn.Module이 모델 구조를 정의한 것처럼, Entity는 데이터 구조(DB 테이블)를 정의한 클래스라고 생각하면 이해가 쉽다.


Spring Data JPA와 Entity가 무엇인지에 대해 대략적으로 감이 잡혔다.

이제 질문을 이해해보자.

 

"Spring Data JPA에서 새로운 Entity인지 어떻게 판단할까?"는 이렇게 풀어서 쓸 수 있다.

 

Spring Data JPA에서 save()를 호출할 때, 이 객체가 새 데이터인지 기존 데이터인지 어떻게 판단하나요?

 

Spring에서는 DB에 객체(Entity)를 저장할 때 save() 메서드를 사용하는데, 당연하게도 이때 객체가 ‘새로운 데이터’인지 ‘기존 데이터’인지에 따라 저장 방식이 달라진다.

  • 새로운 데이터 → INSERT
  • 기존 데이터 → UPDATE

하지만 때때로 ID를 직접 설정하거나 특수한 구조를 사용할 경우, Spring이 이걸 새 데이터인지 헷갈려 할 수 있다.

그래서 이 질문의 의도는 다음과 같다.

이 질문의 의도는 Spring이 어떤 기준으로 새로운 Entity를 판단하는지, 그리고 그 판단 기준이 원하는 대로 작동하지 않을 경우 개발자가 어떻게 개입할 수 있는지를 파악하고자 한 것이다.

 


답변

Spring은 내부적으로 다음과 같은 방법으로 객체가 새 Entity인지 판단한다.

1. ID(@Id) 필드가 null이면 → 새 데이터

생각해보면 당연하다.

새 Entity라면 값이 비어있을 것이기 때문이다.

따라서 ID 값이 비어 있으면 새 Entity로 간주하고 INSERT 한다.

User user = new User();
user.setName("my_Name");
// ID는 비어 있음
userRepository.save(user); // INSERT 실행

 

 

2. ID가 있으면 → 기존 데이터라고 간주할 수 있음

1번 경우와 반대로 ID 값이 존재하면 Spring은 이를 “이미 DB에 있는 데이터”로 보고 UPDATE하려고 시도한다.

이 때, 문제가 발생할 수 있다.

실제로는 이 ID가 DB에 존재하지 않을 수도 있기 때문이다.

예를 들면, 사용자 ID를 다른 시스템에서 받아서 그대로 쓴다고 가정하자. 외부 시스템에서 사용자 ID를 받았으니 그 ID는 있지만, 실제 DB에는 존재하지 않는다. 이런 경우 오류가 발생할 수 있다.

User user = new User();
user.setId(1L); // ID 직접 지정
user.setName("my_name");
userRepository.save(user); // 존재하지 않으면 UPDATE 실패

 

그럼 어떻게 해결해야할까?

 

해결책: Persistable 인터페이스로 직접 알려주기

위와 같은 문제는 Spring한테 새로운 데이터라고 직접 알려줘서 해결하면 된다.

그럼 어떻게 알려줘야 할까?

 

Spring에는 Persistable라는 인터페이스가 있다.

PersistableSpring Data JPA가 이 객체가 새 데이터인지 아닌지를 개발자에게 직접 묻게 해주는 인터페이스다.

 

클래스에서 Persistable 인터페이스를 구현하고 isNew() 메서드를 오버라이드하면 됩니다.

@Override
public boolean isNew() {
    return true; // 무조건 새 데이터로 인식
}

 

이렇게 하면 Spring은 ID가 있든 없든, isNew()true를 반환하면 INSERT를 수행하기 때문에 문제가 발생하지 않는다.

그런데  @Version이라는 특별한 필드가 영향을 줄 수도 있다.

 

@Version은 무엇인가?

간단히 말해서, @Version이 데이터가 몇 번째로 저장됐는지 기록하는 숫자 필드다.

처음 저장하면 버전이 null이고, 이후엔 1, 2, 3… 이렇게 자동으로 올라간다.

 

그럼 이게 왜 중요할까?

Spring의 저장 방식을 python에 비유하면 다음과 같다.

# Python처럼 생각해보자
if entity.version is None:
    # 아직 저장된 적 없음!
    INSERT
else:
    # 이미 저장된 적 있음!
    UPDATE

즉, version 값이 null이면 Spring은 “이거 처음 저장하는 거네?”라고 보고 INSERT를 한다.

 

근데 이걸 이렇게 작성하면 문제가 생길 수 있다.

@Version
private long version; // 기본형 long은 null이 될 수 없음 → 초기값 0

이 경우 Spring은 version이 항상 0이기 때문에 “값이 있으니까 기존 데이터겠지?” 하고 UPDATE를 시도한다.

그러다 DB에 데이터가 없으면 실패하게 된다.

 

그래서, 대신 이렇게 쓰는게 좋다.

@Version
private Long version; // 래퍼 타입 → null 가능

이렇게 하면 version이 null인 상태에서 INSERT가 정상적으로 작동한다.

 

728x90
반응형
Comments