목차

Hibernate Cache

Hibernate의 기본 캐시 전략

Cuncurrency Strategy

동시성 전략 4가지가 있는데 hibernate 문서 설명이 부족해서 로그를 찍어보며 확인해봄.

기본적으로 evictevictAll은 기본 흐름상에서 Hibernate에 의해 직접 호출되지는 않는다. 다른 메소드들에 의해 필요해 의해 호출된다. 이 두 메소드는 javax.persistence.Cacheevict, evictAll메소드가 실행될 때 호출된다.

테스트시에 쿼리 삭제, 수정 등을 하고서 flush후에 rollback 하면 어떻게 되는지 테스트

READ_ONLY

읽기 전용. 우편 번호처럼 잘 안 변하는 것들에 적합할 듯. Read Only의 의미가 수정만 못하게 하는 것인지 수정과 삭제를 둘 다 못하게 하는 것인지에 대해서는 확실치 않다. 그래서 삭제는 가능한 것으로 가정하고 스토리를 짜면 아래 방식으로 했을 때 잘 작동한다. 삭제도 못하게 하려 한다면 lockItem에서도 예외를 던져야 하는 것이 맞아 보인다.

@org.hibernate.annotations.Immutable로 지정된 엔티티와 컬렉션에 사용하는 것이 좋을 듯 하다.

NONSTRICT_READ_WRITE

엄격하지 않은 읽기/쓰기. 객체 동시 수정 등에 대한 고려를 하지 않고 캐싱을 한다. 이 방식은 하나의 객체가 동시에 수정될 가능성이 거의 없을 때 사용한다.

동시 수정이 적은 데이터에 대한 분산 캐시에서는 이것이 적합해 보인다.

READ_WRITE

엄격한 읽기/쓰기로 두개 이상의 쓰레드에서 동시 수정할 가능성에 대해 고려하고 만들어야 한다. READ_WRITE + 클러스터링 캐시 구현체를 사용할 경우 캐시 구현체는 Lock 기능을 제공해야만 한다. 객체 생성, 수정시에 캐시 서버에 대한 접근이 매우 빈번하여 분산 캐시에서는 성능이 떨어질 수 있다. 아래는 Memcached기준으로 생각해본 구현전략.

TRANSACTIONAL

JTA에서만 사용한다.

Hibernate Cache 활성화

Map<String,Object> props = new HashMap<String,Object>();
 
// hibernate.cache.use_second_level_cache
props.put(AvailableSettings.USE_SECOND_LEVEL_CACHE, true); 
 
// hibernate.cache.use_query_cache
props.put(AvailableSettings.USE_QUERY_CACHE, true);
 
// hibernate.cache.region.factory_class - 캐시 구현체 지정
props.put(AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName());
 
// hibernate.cache.region_prefix
props.put(AvailableSettings.CACHE_REGION_PREFIX, "cachetest");
 
// hibernate.cache.default_cache_concurrency_strategy
props.put(AvailableSettings.DEFAULT_CACHE_CONCURRENCY_STRATEGY, CacheConcurrencyStrategy.READ_WRITE); 
 
// ...
EntityManagerFactory emf = Persistence.createEntityManagerFactory("cachetest", props);

JPA

@Cache

@Cache(
    CacheConcurrencyStrategy usage();                      (1)
    String region() default "";                            (2)
    String include() default "all";                        (3)
)

Entity Cache

@Entity
@Table(name = "books")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "books")
public class Book implements Serializable {
....
}

Entity Collection Cache

기본

엔티티의 컬렉션을 캐시하려면 해당 컬렉션에 @Cache 애노테이션을 붙여야 한다.

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() {
    return tickets;
}

양방향 관계의 경우 명시적으로 Collection 쪽에 수정이 발생해야만 캐시가 갱신된다.

OneToOne not owning size

Query Cache

Spring Data JPA Query Cache

public interface UserRepository extends Repository<User, Long> {
 
  @QueryHints(value = {
              @QueryHint(name = "org.hibernate.cacheable", value = "true"),
              @QueryHint(name = "org.hibernate.cacheRegion", value = "user-by-lastname")
              })
  Page<User> findByLastname(String lastname, Pageable pageable);
}

Evict All

현재 Hibernate는 모든 리젼(Region)을 evict하려면 다음을 호출해야 한다.

org.hibernate.Cache cache = sessionFactory.getCache();
cache.evictEntityRegions();
cache.evictQueryRegions();
cache.evictDefaultQueryRegion();
cache.evictCollectionRegions();

Cache 관련 Properties

Query 실행 후 Entity Cache 갱신 문제

참조문서