Search

JPA 1차 캐시와 2차 캐시

생성일
2023/09/02 11:11
태그
spring
Database
상태
Done

JPA의 캐싱

네트워크를 통해 데이터베이스에 접근하는 시간은 서버 내부에서 메모리에 접근하는 시간에 비해 수만배 정도 느리다. 그렇기 때문에 조회한 데이터를 메모리에 캐싱해서 데이터베이스에 접근하는 횟수를 줄이는 것이 효율적이다.
JPA의 영속성 컨텍스트 내부에는 Entity를 보관하는 저장소가 있는데 이를 1차 캐시라 한다. 대부분의 웹 어플리케이션 환경은 트랜잭션을 시작하고 종료할 때까지만 1차 캐시가 유효하기 때문에, 1차 캐시만으로는 DB 접근 횟수를 획기적으로 줄이지 못한다. 이 때문에 하이버네이트를 포함한 대부분의 JPA 구현체들은 어플리케이션 범위의 캐시를 지원하는데 이를 2차 캐시 혹은 공유 캐시라고 한다.

1차 캐시

영속성 컨텍스트 내부에 있는 Entity 저장소로, 엔티티 매니저를 통해 조회하거나 변경하는 모든 엔티티는 1차 캐시에 저장된다. 매 수정마다 DB에 접근하는게 아니라, 엔티티 매니저로 트랜잭션을 커밋하거나 플러시를 호출할 때 1차 캐시에 있는 엔티티의 변경 내역을 DB에 동기화한다.
1차 캐시는 다음과 같은 특징을 가진다.
영속성 컨텍스트 자체가 사실상 1차 캐시로, 1차 캐시는 켜고 끌 수 있는 옵션이 아니다.
같은 엔티티는 같은 영속성 컨텍스트이므로, 객체 동일성(a == b)을 보장한다.
다만 JPA에서 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고, 트랜잭션을 종료할 때 영속성 컨텍스트도 종료한다. 그렇기 때문에 위에서도 언급했듯이 1차 캐시도 트랜잭션을 시작할 때부터 종료할 때까지만 유효하다. 이로 인해 동일한 데이터를 사용해야하더라도 서로 다른 트랜잭션이라면 DB에서 다시 조회해오게 된다. 이를 해결하기 위해 하이버네이트나 다른 JPA 구현체들은 2차 캐시를 지원한다.

2차 캐시

어플리케이션에서 공유하는 캐시를 공유 캐시 혹은 2차 캐시라 부르고, 어플리케이션 범위의 캐시로 어플리케이션이 종료될 때까지 캐시를 유지한다. 2차 캐시를 적용하면 엔티티 매니저를 통해 데이터를 조회할 때 2차 캐시에서 우선적으로 찾고, 없을 때 DB에서 조회한다. 이를 통해 DB 조회 횟수를 획기적으로 줄일 수 있다.
2차 캐시는 다음과 같은 특징을 가진다.
캐싱한 엔티티를 그대로 반환하면 여러 스레드에서 동시에 수정하는 동시성 문제가 발생할 수 있기 때문에, 동시성을 극대화하기 위해 캐싱한 엔티티를 직접 반환하지 않고 복사본을 만들어 반환한다.
엔티티 수준만 캐싱이 되고, DTO 단위의 캐싱은 되지 않는다는 단점이 있다. 이 이유와 분산 시스템으로의 확장성 때문에 실무에서는 2차 캐시는 잘 사용되지 않고, redis나 외부의 cache storage 전략을 사용한다.
2차 캐시는 DB의 PK를 기준으로 캐싱하지만, 객체를 복사해서 사용하기 때문에 영속성 컨텍스트가 다르면 객체의 동일성을 보장하지 않는다.

참고