save() 한 줄 뒤에서 무슨 일이 일어나는가 — JPA 내부 6단계

seonwoo_jung·2025년 7월 16일

1. 도입

요즘 실무에서 대세인 비동기 논블로킹 WebClient는 내부적으로 Reactor Netty와 같은 비동기 HTTP 클라이언트를 사용한다.
WebClient는 높은 추상화를 제공해 webClient.get().retrieve() 같은 한 줄로 요청과 응답을 처리할 수 있으며, 그 내부에는 HTTP 연결, 직렬화/역직렬화, 예외 핸들링 분기등이 숨겨져 있는 복잡한 논블로킹 구조가 존재한다.

단순히 추상화된 API만 바라보고 있으면, 문제가 터졌을 때 “도대체 어디서 부러졌지?” 하고 헤맬 수밖에 없다.
Spring Data JPA도 마찬가지다. save() 한 방으로 끝내주는 것처럼 보이지만, 내부에서는 Hibernate라는 구현체 위에서 다음 흐름을 탄다.

  1. EntityManagerFactory(구현체는 SessionFactory) 생성
  2. EntityManager(구현체는 Session)획득
  3. 트랜잭션 시작
  4. 엔티티 생성 및 설정
  5. em.persist(...)
  6. 트랜잭션 커밋

한 줄 요약하자면, Spring Data JPA는 이 과정을 메서드 호출과 AOP로 ‘감춰둔’ 것이다.


2. 실행 흐름 내부 디버깅

실제 문제가 발생했을 때 위 6단계 어디에 걸려 있는지를 알아야 해결이 빠르다.
아래 각각의 핵심 메서드를 디버그 모드로 찍어보면, 어떤 구조를 따라 움직이는지 더 명확해진다.

createEntityManagerFactory()

• JPA 구현체를 플러그인처럼 로드하는 구조.
• persistence.xml 또는 spring.factories에 등록된 퍼시스턴스 유닛을 찾아 EMF를 반환한다.
• 이 시점에 설정 오류나 클래스패스 이슈가 있으면 애플리케이션이 아예 기동되지 않는다.


createEntityManager()

• Factory가 닫혔는지 검사하고, SessionFactory로부터 Session(=EntityManager)을 꺼낸다.
• 트랜잭션과 자동 동기화되어 flush 타이밍을 보장한다.
• 이 단계에서 “No EntityManager with actual transaction available” 에러가 뜨면 트랜잭션 어노테이션(@Transactional) 누락을 의심해봐야 한다.


em.getTransaction()

• JTA 환경에선 직접 제어를 금지하니, 로컬 트랜잭션인지 체크한다.
• 잘못된 트랜잭션 매니저 설정 때문에 여기서 막히는 경우가 꽤 많다.


begin()

• 이미 열려 있는 트랜잭션이 있는지, 세션이 닫혔는지를 확인한다.
• JDBC/JTA 트랜잭션을 실제로 시작.
• ‘중복 트랜잭션’ 예외가 자꾸 뜬다면, 이 로직을 보면서 AOP 설정을 다시 점검해보자.


persist()

• 1차 캐시에 엔티티를 등록하고, 실제 SQL은 flush 시점까지 지연 저장.
• 배치 INSERT, 롤백 대비를 위해 SQL을 모아두는 구조다.
• @BatchSize 또는 spring.jpa.properties.hibernate.jdbc.batch_size 설정이 잘못되면 예상보다 많은 쿼리가 나갈 수 있다.


commit()

• 내부에서 flush() → 실제 SQL 전송 → 트랜잭션 커밋 순으로 호출된다.
• 커밋 후에는 1차 캐시와 쓰기 지연 큐가 초기화되어 다음 트랜잭션을 위해 깨끗한 상태로 돌아온다.


3. 결론

지금까지 살펴본 6단계 흐름을 머릿속에 그릴 수 있으면, save() 한 줄 뒤에서 무슨 일이 일어나는지 명확하게 파악할 수 있다.
• EMF 생성에서 클래스패스·설정 오류를 잡고,
• EntityManager 획득 단계에서 트랜잭션 어노테이션 누락을 의심하며,
• persist ↔ commit 사이에서 지연 SQL과 배치 INSERT를 검증한다.

여기에 SQL 로그, Hibernate Statistics, P6Spy를 곁들이면 문제 원인 탐색 속도가 확실히 올라간다.
다음번에 save() 한 줄로 인한 에러나 성능 저하가 생겼을 때, 이제는 당황하지 말고 단계별로 파고들어 보자.

Hibernate Statistics란?

예를 들면 1차 캐시 히트/미스, SQL 쿼리 실행 횟수, 엔티티 로딩 수, 지연 로딩 횟수 등을 정량적으로 기록해주는 진단 도구다.

즉, Hibernate Statistics는 JPA/Hibernate 성능 분석의 내부 계기판(Dashboard) 같은 역할이라고 생각하면 된다.

참고 자료

  • Jakarta Persistence Specification (2.2) Section 7
  • Hibernate User Guide - Bootstrap
  • Spring Reference - Transaction Management

0개의 댓글