[JPA] save()는 두 번인데, INSERT는 한 번만? - 영속성 컨텍스트

cheetah_hong·2025년 9월 25일

JPA

목록 보기
1/3

입사 후 급하게 배웠던, 거의 코드 패턴과 눈치로 써먹었던 springboot와 jpa의 개념들을 다시 정리하려고합니다.
(게을렀던 나 회개합니다😇)

착오 예시

Spring Boot + JPA 환경에서 이런 코드를 작성하는 경우가 있습니다.

save()를 두 번 호출

@Service
@RequiredArgsConstructor
public class MemberService {
    private final MemberRepository memberRepository;

    @Transactional
    public void saveTwice() {
        Member member1 = new Member("CHEETAH");

        memberRepository.save(member1);
        memberRepository.save(member1);
    }
}

또는 save()가 내장된 다른 서비스 계층에서 중복 호출의 경우도 생깁니다.
보통 후자의 경우가 많은 것 같습니다.

두 번 호출하는 또 다른 예시

    @Transactional
    public void saveTwice() {
        Member member1 = new Member("CHEETAH");

        memberRepository.save(member1);
        this.memberManageService.manage(member1);
    }
}

이 두 경우 모두 로그를 살펴보면

Hibernate: 
    insert into member (name, id) values (?, ?)
    ~...
    ~...

처럼 INSERT 쿼리가 한 번만 실행됩니다.
이유는 JPA의 영속성 컨텍스트 때문입니다.

영속성 컨텍스트?🤨

JPA의 기본 동작 원리를 짚어보겠습니다.

Spring Data JPA의 save()는 내부적으로 상황에 따라 다음과 같이 동작합니다.

  • 새로운 엔티티 → EntityManager.persist() 호출
  • 이미 관리 중인 엔티티 → EntityManager.merge() 호출

즉, 첫 번째 save() 호출 시 엔티티는 영속성 컨텍스트에 등록,
두 번째 호출에서는 이미 관리되고 있는 객체라, 새로운 INSERT 쿼리를 만들 필요가 없게 됩니다.

영속성 컨텍스트는 쉽게 말해 엔티티를 영구 저장하는 환경 + 상태 변화를 추적하는 1차 캐시입니다.

  • 같은 엔티티를 여러 번 조회해도 동일 객체 반환
  • 트랜잭션 커밋 시점이나 flush() 시점에 DB에 SQL 실행
  • 변경된 값만 감지하여 자동으로 UPDATE 수행 (더티 체킹)

flush/clear 사용시

    @Transactional
    public void saveTwiceWithFlush() {
 		Member member = new Member("CHEETAH");

        memberRepository.save(member);
        em.flush();   //  DB 반영
        em.clear();   // 영속성 컨텍스트 초기화

        memberRepository.save(member); // 새 엔티티처럼 처리됨
    }
}

로그

Hibernate: 
    insert into member (name, id) values (?, ?)
Hibernate: 
    insert into member (name, id) values (?, ?)   

👉 INSERT 두 번 실행.

✅ 포인트 정리

  • save() 두 번 호출해도 INSERT가 한 번만 나가는 건 정상 동작
    이유: 영속성 컨텍스트가 같은 엔티티를 관리하고 있어서
  • 동일 엔티티 조회 시 항상 같은 객체 반환 (1차 캐시에서의 선 조회)
  • JPA는 쓰기 지연 + flush 시점에 SQL 실행

🤔 이를 통해 답할 수 있는 질문

  • 영속성 컨텍스트의 역할은 무엇인가?
  • 엔티티 동일성을 어떻게 보장하는가?
  • flush/clear가 어떤 영향을 미치는가?
profile
치타는 지금 웃고있다 🐆

0개의 댓글