JPA

JPA 영속성과 캐시의 관계 – 캐시처럼 동작하는 영속성 컨텍스트

초코너무조코 2025. 4. 24. 18:49
728x90

JPA = ORM + 캐시?

JPA를 쓰다 보면 마치 자동으로 캐시를 써주는 것 같은 경험을 하게 됩니다. 같은 데이터를 여러 번 조회해도 SQL 쿼리가 한 번만 날아가고, 트랜잭션 내에서 바뀐 값이 자동으로 DB에 반영되기도 하죠. 이 모든 비밀은 영속성 컨텍스트에 있습니다.


1. 영속성 컨텍스트는 1차 캐시다

JPA에서 영속성 컨텍스트1차 캐시 역할을 합니다.

  • 1차 캐시란?
    • 트랜잭션 범위 내에서만 유효한 메모리 캐시입니다.
    • 동일한 EntityManager에서 같은 엔티티를 여러 번 조회해도 DB에서 재조회하지 않고 캐시에서 반환합니다.

2. persist()와 캐시의 관계

📍 persist() 호출 시

  • 엔티티는 영속성 컨텍스트에 저장됩니다.
  • 이후 해당 엔티티는 1차 캐시에 존재합니다.
  • 같은 엔티티를 다시 조회하면 DB로 가지 않고 캐시에서 조회합니다.
em.persist(member);  // 영속성 컨텍스트에 저장 (캐시에 들어감)
Member findMember = em.find(Member.class, member.getId()); // 캐시에서 조회

3. persist() 없이 조회하면?

📍 persist() 안 하고 find() 하면?

  • 영속성 컨텍스트에 없으면 DB에서 조회합니다.
  • 그리고 조회된 엔티티는 자동으로 영속성 컨텍스트에 저장됩니다. 즉, 한 번 DB에서 가져온 후에는 캐시에 저장돼서 다음엔 DB 안 가요!
Member findMember1 = em.find(Member.class, 1L); // DB 조회 → 캐시에 저장
Member findMember2 = em.find(Member.class, 1L); // 캐시에서 조회

4. 정리: 캐시 동작 흐름

상황 동작 방식
persist() 후 조회 캐시에서 조회
persist() 없이 첫 조회 DB에서 조회 후 캐시에 저장
동일 트랜잭션 내 같은 엔티티 재조회 캐시에서 조회 (DB 접근 안 함)
다른 트랜잭션에서 조회 새로운 영속성 컨텍스트, DB 재조회

5. 왜 이게 중요한가?

  • 성능 최적화: 트랜잭션 내에서 동일한 엔티티는 한 번만 DB에서 가져오면 됩니다.
  • 데이터 일관성: 같은 트랜잭션 내에서 항상 같은 객체 인스턴스를 반환합니다.
  • 자동 변경 감지: 캐시된 엔티티의 값을 바꾸면 커밋 시 자동으로 UPDATE 됩니다.

6. 실전 예제

EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();

Member member1 = em.find(Member.class, 1L); // DB 조회
Member member2 = em.find(Member.class, 1L); // 캐시에서 조회

System.out.println(member1 == member2); // true (같은 객체)

tx.commit();
em.close();

6에 대한 의문점 -> 예제에는 persist()가 없는데?

🔑 핵심 포인트: find()도 자동으로 영속성 컨텍스트에 저장해!


📍 정리하자면

  • persist()는 새로운 엔티티를 영속성 컨텍스트에 등록하는 역할이야.
    • 즉, 비영속 → 영속 상태로 바꿔줌.
  • 반면 find()는,
    • 먼저 영속성 컨텍스트(1차 캐시) 를 확인하고,
    • 없으면 DB에서 조회 후, 그 엔티티를 영속성 컨텍스트에 자동으로 등록해.

💡 즉, find() → "조회 + 캐시에 자동 등록"

// DB 조회 후 -> 영속성 컨텍스트에 저장 
Member member1 = em.find(Member.class, 1L); 
// 캐시에서 바로 조회
Member member2 = em.find(Member.class, 1L); 
System.out.println(member1 == member2); // true (같은 인스턴스)
  • 첫 번째 find()는 DB에서 가져오고, 그 엔티티는 자동으로 영속성 컨텍스트에 등록됨.
  • 두 번째 find()는 이미 캐시에 있으니, DB 접근 없이 캐시에서 반환.

🎯 persist()와 find() 차이

메서드역할
persist() 새 엔티티를 영속성 컨텍스트에 등록 (DB에는 아직 INSERT 안됨)
find() DB에서 엔티티 조회 → 자동으로 영속성 컨텍스트에 등록

의문점에 대한 최종 정리

  • persist()가 없어도 find()는 영속성 컨텍스트에 자동 등록하니까,
  • 트랜잭션 안에서 한 번 DB 조회 → 이후 캐시에서 조회 구조가 되는 거야.

 

🔥 결론

  • JPA에서 영속성 컨텍스트는 1차 캐시로 동작한다.
  • persist()하면 캐시에 저장되고, find()도 내부적으로 캐시 확인 후 DB 조회한다.
  • 트랜잭션 내에서는 DB 접근 최소화, 객체 일관성 유지가 가능하다.

 

728x90