[Spring] Spring Cache 어노테이션

2025. 5. 15. 19:06·Spring

🛠️ Spring Boot Cache 어노테이션

 

어노테이션 명 설명
@EnableCaching Spring Boot에서 캐시 활성화를 위해 사용하는 어노테이션이다. 보통 Spring Boot의 메인 메서드가 선언되어 있는 클래스나, Spring Cache 관련 설정 파일에 선언한다.
@Cacheable 메서드 실행 결과를 캐시에 저장하고, 동일한 Key로 요청이 오면 캐시된 값을 반환한다.
@CacheEvict 지정된 캐시를 제거한다.
@CachePut 메서드 실행 결과를 항상 캐시에 저장한다. @Cacheable은 기존에 캐시가 있으면 메서드를 실행하지 않지만, @CachePut은 항상 실행하고 새로운 값을 강제로 덮어쓴다.
@Caching 여러 개의 캐시 어노테이션을 하나의 메서드에 동시 적용할 수 있게 해준다.

 

 

 

⚙️ @Cacheable

 

@Cacheable은 우리가 캐시 기능을 구현할 때 가장 많이 사용하는 어노테이션이다.

 

 

아래는 @Cacheable을 사용해 제품 리스트를 캐시로 조회하는 코드이다.

 

@Cacheable(value = "productList", key = "#request.toCacheKey()")
public ProductListResponse findProducts(ProductFindListServiceRequest request) {
    ...
}

 

 

여기서 @Cacheable 어노테이션 옆에 두 가지 속성이 입력되어 있는데, @Cacheable 어노테이션에서 사용가능한 속성은 다음과 같다.

 

속성 설명
value 캐시 이름(공간)
key 캐시를 구분하는 키
condition 캐시 저장 여부를 조건식으로 제한
unless 메서드 실행 후 결과값에 따라 캐시 저장 여부 결정 (ex) null일 경우 저장 X)

 

 

🔹 @Cacheable.value

 

캐시 저장소 이름을 지정할 때 사용한다.

 

 

만약 캐시 저장소를 커스텀 하고 싶으면 다음과 같이 설정 코드를 작성하면 된다.

 

@EnableCaching
@Configuration
public class CachingConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("productList");
        cacheManager.setCaffeine(
                Caffeine.newBuilder()
                        .expireAfterWrite(10, TimeUnit.MINUTES)  // 캐시 TTL 설정
                        .maximumSize(1000)                      // 최대 캐시 수 제한
        );
        cacheManager.setAllowNullValues(false);  // null 캐싱 방지
        return cacheManager;
    }
}

 

 

만약 커스텀할 필요가 없으면 따로 코드를 작성하지 않아도 된다.

 

 

만약 따로 설정 코드를 작성하지 않으면 value에 작성된 이름으로 캐시 저장소가 생성된다.

 

 

🔹 @Cacheable.key

 

캐시 데이터를 조회하기 위해선 입력한 Key가 캐시 저장소에 존재해야 한다.

 

 

캐시는 아래와 같이 캐시용 저장소에 Key-Value 형태로 저장되어 있기 때문이다. (현재 내가 사용 중인 캐시 저장소는 Caffeine Cache이다)

 

 

다음은 요청 DTO에서 Key를 생성하는 코드이다.

 

@Getter
public class ProductFindListServiceRequest {
    private final Long productId;
    private final String sorter;
    private final String keyword;
    private final Long lastSortValue;

    ...

    public String toCacheKey() {
        return String.join(":",
                String.valueOf(sorter),
                String.valueOf(keyword),
                String.valueOf(productId),
                String.valueOf(lastSortValue)
        );
    }
}

 

 

❗️ ProductFindListServiceRequest 입력 값

{
    "productId": 100,
    "sorter": "recent",
    "lastSortValue": 0,
    "keyword": ""
}

 

 

toCacheKey()을 통해 생성된 Key는 ‘recent::100:0’ 이런 형태이다.

 

 

🔹 @Cacheable.condition

 

condition 속성은 만약 @Cacheable 어노테이션이 달린 메서드가 호출되면 캐시에서 먼저 조회할지, 메서드부터 먼저 실행할지 결정할 때 사용된다.

 

  • condition이 true : 캐시부터 먼저 조회하고, 캐시 저장소에 데이터가 없으면 캐시를 저장함
  • condition이 false : 캐시를 사용하지 않고, 항상 메서드만 실행됨
@Cacheable(
    value = "productList",
    key = "#request.toCacheKey()",
    condition = "#request.sorter == 'recent'"
)

 

 

위 코드는 제품 정렬 기준이 ‘등록순’ 일 때만 캐시가 사용된다.

 

 

만약 ‘댓글 많은 순, 주문 많은 순’일 경우 캐시 저장소를 조회하지도 않고, 캐시를 저장하지도 않는다.

 

 

 

🔹 @Cacheable.unless

 

위에 정리했던 condition은 메서드 실행 전 요청 데이터를 토대로 캐시 작업을 수행할지 안 할지 결정한다.

 

 

unless 속성은 condition과 반대로 응답 데이터를 토대로 데이터를 캐시 할지 안 할지 결정한다.

 

@Cacheable(
    value = "productList",
    key = "#request.toCacheKey()",
    unless = "#result == null or #result.productResponses.isEmpty()"
)

 

 

위 코드는 결과값이 null이거나 empty일 경우 캐시 작업을 수행하지 말라는 것이다.

 

 

 

⚙️ @CacheEvict

 

@CacheEvict은 캐시를 삭제할 때 사용하는 어노테이션이다.

 

 

보통 @CacheEvict은 데이터를 수정하거나 삭제하는 작업에 자주 사용된다.

 

 

그 이유는 만약 데이터에 변경이 발생한 경우, 캐시 데이터에는 변경 이전의 데이터가 저장되어 있기 때문이다.

 

@CacheEvict(value = "productList", key = "#request.toCacheKey()")
public void updateProduct(ProductUpdateRequest request) {
    // 제품 정보 수정 로직
}

 

@CacheEvict(value = "productList", key = "#productId")
public void deleteProduct(Long productId) {
    // DB에서 제품 삭제
}

 

 

다음과 같이 캐시 저장소를 지정하고, 삭제할 캐시 데이터의 Key을 설정하면 된다.

 

 

그런데 여기서 문제가 하나 생기는데, 내가 현재 사용 중인 캐시 방식은 제품 데이터 리스트를 캐시로 저장한다.

 

 

그런데 리스트 내부에 있는 데이터가 변경된다면??

 

 

내가 사용중인 Key에는 요청 DTO 정보만 들어있기 때문에 내부에 어떤 데이터가 저장되어 있는지는 Key을 통해 알 수 없다. (캐시 저장소의 Value에 있는 데이터를 일일이 탐색해야 함)

 

 

이 점에 대해 한번 고민해 보자..

 

 

 

⚙️ @CachePut

 

@CachePut은 캐시 저장소에 Key와 일치하는 데이터가 있든 말든 일단 메서드를 먼저 실행하고, 응답 데이터를 캐시 저장소에 저장할 때 사용되는 어노테이션이다.

 

@CachePut(value = "productList", key = "#product.id")
public Product updateProduct(Product product) {
    // DB 업데이트 로직
    return updatedProduct;
}

 

 

보통 데이터도 수정하면서 캐시도 동시에 갱신하고 싶을 때 사용된다.

 

 

이를 통해 다음 조회 요청 때도 캐시를 사용할 수 있다.

'Spring' 카테고리의 다른 글

[Spring] Spring Cache  (0) 2025.05.15
[Spring] Spring Security 정리  (0) 2025.05.01
[Spring] MySQL, MongoDB 전략 패턴  (0) 2025.04.23
[Spring] Spring 프로젝트 SonarQube 연동  (0) 2025.01.09
[Spring] Spring Batch를 사용한 대량 데이터 저장 (2)  (0) 2024.12.22
'Spring' 카테고리의 다른 글
  • [Spring] Spring Cache
  • [Spring] Spring Security 정리
  • [Spring] MySQL, MongoDB 전략 패턴
  • [Spring] Spring 프로젝트 SonarQube 연동
오도형석
오도형석
  • 오도형석
    형석이의 성장일기
    오도형석
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • MSA 모니터링 서비스
        • DB
      • 스파르타 코딩클럽
        • SQL
        • Spring
      • 백엔드
        • Internet
        • Java
        • DB
      • 캡스톤
        • Django
        • 자연어처리
      • Spring
        • JPA
        • MSA
      • ETC
        • ERROR
      • 개발 일기 N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 인기 글

  • 태그

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
오도형석
[Spring] Spring Cache 어노테이션
상단으로

티스토리툴바