백엔드 면접 용어 사전
Spring·JPAsnapshot · loadedState

스냅샷

엔티티를 조회한 순간의 필드 값을 통째로 복사해 둔 배열. 변경 감지가 이것과 현재 값을 비교한다.

엔티티를 조회한 순간의 필드 값들을 그대로 복사해 둔 배열. 하이버네이트 내부에서는 EntityEntry.loadedState 라는 이름의 Object[] 로 들고 있다.

왜 필요한가

JPA는 setter가 호출됐다는 사실을 알 방법이 없다. 자바에는 "이 필드가 바뀌었다"를 알려 주는 훅이 없기 때문이다. 그래서 처음 값을 따로 적어 두고 나중에 대조하는 방식을 쓴다. 이 적어 둔 값이 스냅샷이다.

메모리에 어떻게 놓이는가

Member(id=1, name="김", age=20) 을 조회하면 힙에 두 덩어리가 생긴다.

다이어그램 로딩 중…
  • 엔티티 인스턴스 — 우리가 setter로 만지는 실제 객체
  • 스냅샷 배열 — 조회 시점 값의 사본. 엔티티와 별개의 메모리에 있다

m.setName("이") 를 하면 엔티티 인스턴스의 name"이"로 바뀌고, 스냅샷 배열은 여전히 [1, "김", 20] 이다. 이 차이가 변경의 증거가 된다.

언제 만들어지고 언제 사라지나

시점스냅샷
find()·JPQL로 조회생성
persist() 로 새로 저장생성(INSERT 이후 값 기준)
flush현재 값과 비교 후, 보낸 값으로 갱신
트랜잭션 종료·detach()폐기

비용 — 그래서 readOnly가 의미 있다

엔티티 하나당 필드 수만큼 배열이 하나 더 생긴다. 1만 건을 조회하면 엔티티 1만 개 + 스냅샷 배열 1만 개가 힙에 올라간다.

조회만 하는 트랜잭션에 @Transactional(readOnly = true) 를 붙이면 하이버네이트가 flush 모드를 MANUAL로 두고 스냅샷을 만들지 않는다. 메모리와 비교 비용이 함께 사라진다. 대량 조회에서 체감이 크다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — Spring·JPA — IoC/DI·AOP·영속성 컨텍스트·N+1