[JPA 기본] JPA Cache
포스트
취소

[JPA 기본] JPA Cache

1차 캐시

  • 영속성 컨텍스트 내부에는 엔티티를 보관하는 저장소
    • 트랜잭션이 시작하고 종료할 때 까지만 1차 캐시가 유효하다. (일반적인 경우)
    • 클라이언트의 요청이 들어올 때부터 끝날때 까지만 1차 캐시가 유효하다. (OSIV를 사용하는 경우)
  • 데이터베이스 접근 횟수를 획기적인 정도로 줄여주는 건 아니다.
  • Entity Manager로 조회하거나 변경하는 모든 엔티티는 1차 캐시에 저장된다.
  • 1차 캐시는 임의로 on/off할 수 있는 옵션이 아니다.
  • 영속성 컨텍스트 자체가 사실상 1차 캐시와 같다고 볼 수 있다.
  • 동작 순서
    1. find 호출
    2. 영속성 컨텍스트에 캐시된 데이터 조회
    3. if(Data X) DB 접근 및 데이터 로드 후 1차 캐시 데이터에 저장
    4. 결과 반환
  • 단, 최초 조회시에는 바로 DB에서 조회한다.
  • 같은 엔티티를 조회하는 경우에 1차 캐시에에서 조회한다.

2차 캐시 (= 공유 캐시)

  • 하이버네이트를 포함한 대부분의 JPA 구현체들이 지원하는 애플리케이션 범위의 캐시
  • 애플리케이션을 종료할 때까지 유지되는 캐시
  • 분산 캐시나 클러스터링 환경의 캐시는 애플리케이션보다 더 오래 유지 될 수도 있다.
  • 동작 순서
    1. find 호출
    2. 2차 캐시에서 우선조회
    3. if(Data X) DB 접근 및 데이터 로드 후 2차 캐시 데이터에 저장
    4. 해당 엔티티를 복사
    5. 복사한 엔티티를 반환
  • 2차 캐시를 적절히 활용하면 데이터베이스 조회 횟수를 획기적으로 줄일 수 있다.
  • 1차 캐시와 다르게 조회환 엔티티가 아닌 조회한 엔티티의 복사복을 반환한다.
  • 2차 캐시는 영속성 유닛 범위의 캐시다.
  • 2차 캐시도 데이터베이스 기본 키를 기준으로 캐싱한다.
    • 단, 영속성 컨텍스트가 다르면 동일성을 보장하지 않는다.

2차 캐시 사용법 - 공통

  • @Cacheable : 엔티티 캐시 적용시 사용하는 어노테이션
  • 캐시 모드 설정 (properties 파일에서 설정)
    • 예시 : spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE
    • 속성 종류 (1) ALL : 모든 엔티티를 캐시한다. (2) NONE : 캐시를 사용하지 않는다. (3) ENABLE_SELECTIVE : Cacheable(true)로 설정된 엔티티만 캐시를 적용한다. (주사용) (4) DISABLE_SELECTIVE : 모든 엔티티를 캐시하는데 Cacheable(false)만 캐시하지 않는다 (5) UNSPECIFIED : JPA 구현체가 정의한 설정을 따른다
  • 캐시 모드 설정 방법 (properties 파일에 속성 값 추가하기)
    #캐시 모드 설정
    spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE
    
  • 캐시 조회 모드 설정
    • USE : 캐시에서 조회한다. (기본값)
    • BYPASS : 캐시를 무시하고 데이터베이스에 직접 접근한다.
  • 캐시 저장 방식 설정
    • USE : 조회한 데이터를 캐시에 저장. (기본값) (1) 조회한 데이터가 이미 캐시에 있으면 캐시 데이터를 최신 상태로 갱신하지는 않는다. (2) 트랜잭션을 커밋하면 등록/수정한 엔티티도 캐시에 저장한다.
    • BYPASS : 캐시에 저장하지 않는다.
    • REFRESH : USE 전략에 추가로 데이터베이스에서 조회한 엔티티를 최신 상태로 다시 캐시한다.
  • 캐시 조회/저장 방식 설정에 대한 예시
    //Entity Manager 범위 적용
    em.setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);

    //find()
    Map<String, Object> param = new HashMap<String, Object>();
    param.put("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
    param.put("javax.persistence.cache.storeMode", CacheStoreMode.BYPASS);
    em.find(SomeEntity.class, id, param);
    

2차 캐시 사용법 - JPA

  • javax.persistence.Cache 인터페이스 제공
        public interface Cache {
            // 해당 엔티티가 캐시에 있는지 여부 확인
            public boolean contains(Class cls, Object primaryKey);
            // 해당 엔티티중 특정 식별자를 가진 엔티티를 캐시에서 제거
            public void evict(Class cls, Object primaryKey);
            // 해당 엔티티 전체를 캐시에서 제거
            public void evict(Class cls);
            // 모든 캐시 데이터 제거
            public void evictAll();
            // JPA Cache 구현체 조회
            public <T> T unwrap(Class<T> cls);
        }
    
        public interface Cache {
        //캐시 관리 객체 조회
        Cache cache = emf.getCache();
        boolean contains = cache.contains(SomeEntity.class, someEntity.getId());
        }
    

2차 캐시 사용법 - 하이버네이트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- @Cache : 하이버네이트에서 제공하는 캐시 설정 어노테이션
    - 캐시와 관련된 더 세밀한 설정을 할 때 사용
    - 컬렉션 캐시를 적용할 때에도 사용
- @Cache 어노테이션의 속성
    - usage : CacheConcurrencyStrategy 를 사용해서 캐시 동시성 전략을 설정
    (1) NONE : 캐시 설정 X
    (2) READ_ONLY :
        - 읽기 전용 설정
        - 등록/삭제 가능
        - 수정 불가능
        - 읽기 전용인 불변 객체는 수정 X → 2차 캐시 조회 시 객체를 복사하지 않고 원본 객체를 반환
    (3) NONSTRICT_READ_WRITE :
        - 엄격하지 않은 읽고 쓰기 전략
        - 동시에 같은 엔티티 수정 시 데이터 일관성이 깨질 수 있다.
        - EHCACHE는 데이터 수정 시 캐시 데이터를 무효화
    (4) READ_WRITE :
        - 읽기/쓰기 가능
        - READ COMMITTED 정도의 격리 수준을 보장
        - EHCACHE는 데이터 수정 시 캐시 데이터도 같이 수정
    (5) TRANSACTIONAL :
        - 컨테이너 관리 환경에서 사용 가능
        - 설정에 따라 REPEATABLE READ 정도의 격리 수준을 보장
    - region : 캐시 지역 설정
    - include : 연관 객체를 캐시에 포함할지 선택, 종류 : all/non-lazy, 기본값 : all
- 환경설정
    1. 의존성 추가하기
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>5.6.4.Final</version>
        </dependency>
        
        implementation 'org.hibernate:hibernate-ehcache:5.6.4.Final'
        
1
    2. properties 파일에 속성 값 추가하기
        #2차 캐시 활성화
        spring.jpa.properties.hibernate.cache.use_second_level_cache=true
        #2차 캐시를 처리할 클래스를 지정
        spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
        #캐시 적용 여부를 확인 (하이버네이트 자체 제공 기능)
        spring.jpa.properties.hibernate.generate_statistics=true
        
1
2
3
4
5
6
7
8
9
10
- 하이버네이트가 지원하는 캐시
    - 엔티티 캐시
    (1) 엔티티 단위로 캐시한다.
    (2) 식별자로 엔티티를 조회하거나 컬렉션이 아닌 연관된 엔티티를 로딩할 때 사용한다.
    - 컬렉션 캐시
    (1) 엔티티와 연관된 컬렉션을 캐시한다.
    (2) 컬렉션이 엔티티를 담고 있으면 식별자 값만 캐시한다.
    - 쿼리 캐시
    (1) 쿼리와 파라미터 정보를 키로 사용해서 캐시한다.
    (2) 결과가 엔티티면 식별자 값만 캐시한다.
        //Entity Manager 범위 적용
        em.setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);

        //find()
        Map&lt;String, Object&gt; param = new HashMap&lt;String, Object&gt;();
        param.put("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
        param.put("javax.persistence.cache.storeMode", CacheStoreMode.BYPASS);
        em.find(SomeEntity.class, id, param);
        
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.