본문 바로가기

위클리페이퍼

@Cacheable, @CachePut, @CacheEvict에 대해서

이번주 페이퍼1

Spring Cache에서 @Cacheable, @CachePut, @CacheEvict의 차이점과 각각을 어떤 상황에서 사용하는 것이 적절한지 설명해주세요.

 

캐시와 관련된 위클리페이퍼로 보인다

 


 

캐시?

자주 사용되는 데이터를 저장하는 공간이라고 함. 빈번하게 사용되는 데이터를 매번 요청 때마다 생성해서 응답하는것보다 생성된 데이터를 저장해놓고 똑같은 요청이 왔을 때, 로직을 거치지 않고 데이터를 반환해주는 것이 서버 리소스 사용을 줄일 수 있으므로 성능을 향상시킬 수 있다고 한다.

즉 리포지토리를 패싱하고 서비스 - 컨트롤러에서 바로 저장된 값을 반환해줌

 

캐시는 어디에 사용하는 것이 좋은가?

 - 클라이언트에게 전달되는 값이 동일할 때

 - 빈번하게 호출될 때

 - 한 번의 처리에서 서버 리소스를 많이 요구할 때

 

그렇다면 사용되지 말아야 하는 경우는?

 - 실시간으로 정확성을 요구할 때

 - 빈번하게 데이터 변경이 일어날 때

 

 

스프링 설정

build.gradle에 의존성을 추가해준다

implementation 'org.springframework.boot:spring-boot-starter-cache'

 

spring-boot-starter에서 제공하는 캐시는 서버를 끄면 데이터가 날아간다.

데이터를 계속 유지하고 싶다면 redis와 같은 외부 저장소를 이용해야한다고 함

 

Spring AOP 기반으로 캐시가 작동해서 애너테이션을 통해 설정할 수 있어서 간편하다.

@Cacheable, @CachePut, @CacheEvict와 같은 것들로 손쉽게 쓸 수 있다고 함

 

 

@Cacheable

캐시 생성 및 전달을 담당함

캐시에 데이터가 없을 경우, 기존의 로직을 실행하고 캐시에 데이터를 추가한다.

캐시에 데이터가 있다면 캐시의 데이터를 반환한다.

 

@Cacheable("userCacheStore") // 캐시를 저장함
public User cacheable(String date) {
	System.out.println("cacheable 실행");
    // ...
    return user;
}

@Cacheable(value = "userCacheStore", key = "#user.name") // key를 지정한 경우의 캐시 저장
public User cacheableByKey(User user) {
	System.out.println("cacheable 실행");
    // ...
    return user;
}

// 조건부 캐시 저장, value / key / condition
@Cacheable(value = "userCacheStore", key = "#user.name", condition = "user.name.length() > 5")
public User cacheableWithCondition(User user) {
	System.out.println("cacheableWithCondition 실행");
    // ...
    return user;
}

 

1. key를 지정하지 않은 경우

 - 파라미터인 date 값에 2023-01이 처음으로 입력된 경우,

파라미터 2023-01에 대한 캐싱된 데이터가 없기 때문에 메서드가 실행됨

 - cacheable 문자열 출력

 - user이 반환되고 이 반환된 값이 캐시 저장소에 저장됨

 - 다시 2023-01을 파라미터에 넣고 요청함

 - 캐싱되어있기 때문에 캐시 저장소에 저장된 member값이 반환됨

 - "cacheable 실행"이라는 문자열은 출력되지 않는다. 캐시 데이터를 가져왔을 뿐이지 메서드가 실행된 것이 아니기 때문

 

2. key를 지정하는 경우

 - key인 name이 "Alice"라는 member객체가 처음 들어오면, 캐싱 전이기 때문에 "cacheable 실행" 문자열을 출력하고

 - 메서드가 실행된거니까 "Alice" 객체를 가진 user 데이터는 캐싱된다

 - 다시 "Alice" 라는 name을 가진 멤버 객체가 요청되면 캐싱된 멤버 객체가 반환되고 문자열은 출력되지 않는다.

 

3. 조건부 캐싱

 - @Cacheable 애너테이션에 condition 속성을 통해 적용 가능

 - 위의 condition 조건은 필드 값의 길이가 5를 초과하는 경우에만 캐싱되도록 한 것

 

 

@CachePut

캐시 내용 수정을 담당하는 애너테이션

@Cacheable과 유사하게 실행 결과를 캐시에 저장하지만, 조회시에 저장된 캐시 내용을 저장하지 않고 "항상" 메서드를 실행한다.

 

예시

@CachePut(value = "userCacheStore", key = "#user.name") // 항상 메서드 로직을 실행함
public User cachePut(User user) {
	System.out.println("cachePut 실행");
    // ...
    return user;
}

 

 

@CacheEvict

캐시 삭제를 담당하는 애너테이션

@CacheEvict에 캐시 이름을 넣어주면, 메서드가 실행될 때 캐시의 내용이 제거된다.

기본적으로 메서드의 키에 해당하는 캐시만 제거한다.

 

예시

@CacheEvict("userCacheStore") // 캐시 제거 애너테이션 @CacheEvict
public User cacheEvict(Date date) {
	System.out.println("cacheEvict 실행");
    // ...
   return null; // null 반환
}

@CacheEvict(value = "userCacheStore", key = "#user.name") // name키 값을 가진 캐시만 제거함
public User cacheEvictByKey(User user) {
	System.out.println("cacheEvictByKey 실행");
    // ...
    return user;
}

@CacheEvict(value = "userCacheStore", allEntries = true) // 캐시에 저장된 값을 모두 제거
public User cacheEvictAllEntries() {
	System.out.println("cacheEvictAllEntries 실행");
    // ...
    return null; // null 반환
}

// beforeInvocation 속성을 통해 메서드 실행 이후(기본값)나 이전에 제거해야하는지 지정
@CacheEvict(value = "userCacheStore", beforeInvocation = true)
public User cacheEvictBeforeInvocation() {
	System.out.println("cacheEvictBeforeInvocation 실행");
    // ...
    return null; // null 반환
}

 

 

출처

https://hyeri0903.tistory.com/237