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

Spring Boot + JPA 환경에서 이런 코드를 작성하는 경우가 있습니다.
@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()는 내부적으로 상황에 따라 다음과 같이 동작합니다.
즉, 첫 번째 save() 호출 시 엔티티는 영속성 컨텍스트에 등록,
두 번째 호출에서는 이미 관리되고 있는 객체라, 새로운 INSERT 쿼리를 만들 필요가 없게 됩니다.
영속성 컨텍스트는 쉽게 말해 엔티티를 영구 저장하는 환경 + 상태 변화를 추적하는 1차 캐시입니다.
@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 두 번 실행.