CS/JPA

JPA Cache

leah-only 2025. 6. 17. 16:30

⚡ 1차 캐시

 JPA의 영속성 컨텍스트 (Entity Manager) 내부에 있는 메모리 저장소이다. 

엔티티가 영속 상태가 되면 JPA는 이를 1차 캐시에 저장하고

이후 동일한 ID로 조회되는 엔티티는 DB를 거치지 않고 메모리에서 바로 반환한다.

 

✔️ 1차 캐시에 엔티티가 있는 경우 조회 과정

  • 엔티티 조회
  • 1차 캐시에서 결과 반환
Member m1 = em.find(Member.class, 1L); // → DB에서 조회, 1차 캐시에 저장
Member m2 = em.find(Member.class, 1L); // → 1차 캐시에서 즉시 반환
System.out.println(m1 == m2); // true (객체 동일성 보장)

 

✖️ 1차 캐시에 엔티티가 없는 경우 조회 과정

  • 엔티티 조회
  • DB 조회
  • 1차 캐시에 결과 저장
  • 저장한 결과 반환

최종적으로 트랜잭션이 commit 되거나 flush 되면 1차 캐시의 엔티티 변경 내용을 DB에 동기화한다. 

 

🔍 1차 캐시의 특징

  • 영속성 컨텍스트 단위로 존재
    • EnityManager 단위로 1차 캐시가 구성됨
  • 객체 동일성 보장
    • 같은 ID의 엔티티는 항상 동일 객체 (==) 로 관리됨
  • 성능 향상
    • 동일한 엔티티 재조회 시 DB 접근 없이 캐시에서 바로 조회
  • 트랜잭션 범위 내에서만 유효
    • 트랜잭션 종료 시 1차 캐시도 제거됨
  • 쓰기 지연
    • DB로의 반영은 flush/commit 시점에 일괄 처리 됨

 

⚠️ 1차 캐시의 한계

  • 트랜잭션 단위(Entity Manager 단위) 로만 유효
  • 트랜잭션 종료 시 메모리에서 제거
  • 다른 트랜잭션에서는 별도의 캐시 생성, 동일 객체 아님

⚡ 2차 캐시

2차 캐시는 JPA에서 제공하는 애플리케이션 범위의 공유 캐시이다. 

따라서 2차 캐시는 공유 캐시라고도 한다. 

또한 애플리케이션을 종료할 때 까지 캐시가 유지된다. 

각 영속성 컨텍스트와는 무관하게 동작하며 

여러 트랜잭션, 여러 사용자 간에도 엔티티 데이터를 재사용할 수 있도록 한다. 

2차 캐시는 영속성 컨텍스트가 다르면 객체 동일성을 보장하지 않는다. 

 

✔️ 2차 캐시에 엔티티가 있는 경우 조회 과정

  • 엔티티 조회
  • 2차 캐시에서 결과 반환

✖️ 1차 캐시에 엔티티가 없는 경우 조회 과정

  • 엔티티 조회
  • DB 조회
  • 2차 캐시에 결과 저장
  • 2차 캐시는 복사본을 만들어서 1차 캐시에 반환

 


 

🧠 2차 캐시는 왜 복사본을 반환할까?

✔️ 동시성 문제 방지

 

캐시에 있는 원본 엔티티를 그대로 반환하면 여러 스레드 또는 트랜잭션 같은 객체를 동시에 수정할 수 있는 위험이 있음

즉, 멀티 스레드 환경에서 동시성 이슈가 발생할 수 있다. 

 

 

⚙️ 실무에서 2차 캐시

 

✅ 설정이 복잡하고, 한계가 분명

  • Hibernate 2차 캐시 활성화 → @Cache, ehcache, infinispan 등의 설정 필요
  • JPQL, 조건 기반 조회에서는 캐시 효과 없음 → 오직 ID 기반 조회만 캐시 가능

✅ DTO 반환, API 호출 등 복잡한 로직에는 적합하지 않음

  • 그래서 요즘은 Spring Cache (e.g. Caffeine, Redis, EhCache)
    서비스 계층이나 메서드 단위에서 사용하는 방식이 더 보편적이고 강력함

참고:https://github.com/devSquad-study/2023-CS-Study/blob/main/JPA/jpa_cache.md