티스토리 뷰

반응형

Overview

Spring에서 제공하는 caching이라는 기능이 있다. spring caching은 컴퓨터를 하는 사람이면 흔히 알고 있는 개념과 동작이 비슷하다. 여러 번 호출에 대해서 결과값이 비슷하다면 메서드를 직접 실행하지 않고 미리 메모리상에 저장을 해둬서 성능을 높이는 방법이다. 만약 DB 정보가 크게 바뀌지 않는다거나 네트워크를 타야하는 연산이라면 더욱 성능 향상에 도움이 될 것이다. 물론 계산 복잡도가 높은 메서드에 대해서도 많은 이점을 받을 수 있다.

Caching 종류와 사용법

@Cacheable

캐시에서 값을 조회하거나 없으면 메서드를 실행해 값을 캐시에 저장하는 기능을 제공한다.

@Cacheable(key = "#id")
public String getItemById(Long id) {
    System.out.println("Fetching item from database with ID: " + id);
    return "Item-" + id;
}

위 소스코드에서 id를 기반으로 캐싱을 수행하며 최초 수행 시에는 메서드를 모두 실행하지만,

2번째 실행부터는 캐시에 저장된 정보를 먼저 확인해서 값을 반환한다.

 

주요 옵션으로는 아래처럼 사용이 가능하다.

 

  • value / cacheNames: 캐시 이름 지정
    • @CacheConfig에서 공통 캐시 이름을 정의할 수 있으며, 해당 어노테이션의 value와 중복되면 이 설정이 우선
  • key: 캐시에 저장할 키를 지정
    • Spring Expression Language (SpEL)을 사용 가능
    • 기본값: "#root.methodName + #p0" (메서드 이름과 첫 번째 매개변수로 생성)
  • keyGenerator: 캐시 키를 생성할 커스텀 로직을 지정할 때 사용
    • key를 사용하는 대신 커스텀 키 생성기를 정의해야 한다.
  • condition: 특정 조건에 따라 캐싱 여부를 결정
    • SpEL 표현식을 사용하며, 조건이 true일 때만 캐시
  • unless: 결과값이 특정 조건에 해당하면 캐싱하지 않음
    • SpEL 표현식을 사용하며, 조건이 true이면 캐시하지 않음
  • sync: 캐시에 데이터가 없을 때 동시에 여러 스레드가 같은 메서드를 호출하지 못하도록 동기화를 설정
    • 기본값: false

위 옵션에 대한 사용법은 아래와 같다.

@Cacheable(value = "myCache",
	key = "#id",
        keyGenerator = "customKeyGenerator",
        condition = "#id > 10",
        unless = "#result == null",
        sync = true)

 

keyGenerator는 좀 더 다뤄야할 내용이 많으므로 다음 장에서 다루도록 하겠다.

@CachePut

항상 메서드를 실행한 뒤 결과를 캐시에 저장하는 기능을 제공한다.

@CachePut(key = "#id")
public String updateItem(Long id, String updatedItem) {
    System.out.println("Updating item in database with ID: " + id);
    return updatedItem;
}

@CachePut은 @Cacheable과 다르게 항상 메서드를 수행해 결과값을 가져온다.

그러면 CachePut은 사실상 항상 메서드 로직을 타는 것인데 어떤 경우에 사용해야 하는지 의문이 생길 수 있다.

CachePut은 아래와 같은 상황에서 사용하면 유용하다.

캐시 데이터 갱신

  • 캐시된 데이터가 오래되었거나 변경된 경우, 해당 데이터를 갱신해야 한다.
  • 이때 @CachePut은 메서드를 실행해 최신 데이터를 얻고, 캐시에 새 데이터를 업데이트하는 데 사용된다.
@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) { 
	System.out.println("Updating product in database: " + product); 
	return product;
}

캐시 무효화 후 재설정

  • 일부 데이터는 업데이트 이후 재조회하지 않고 곧바로 캐시에 저장되어야 한다
  • @CacheEvict를 사용해 데이터를 지우는 대신, @CachePut을 사용해 데이터를 갱신한다.

특정 조건에서만 캐싱 갱신

  • @CachePut과 condition을 결합해 필요한 경우에만 캐시를 갱신할 수 있다.
     
@CachePut(value = "products", key = "#product.id", condition = "#product.stock > 0") 
public Product updateProductStock(Product product) { 
    System.out.println("Updating product stock: " + product); 
    return product; 
}

 

옵션은 @Cacheable과 동일하므로 생략하도록 하겠다.

@CacheEvict

캐시에서 데이터를 삭제하는 기능을 제공한다.

@CacheEvict(key = "#id")
public void deleteItem(Long id) {
    System.out.println("Deleting item from database and cache with ID: " + id);
}

캐시를 삭제하는 기능이기 때문에 상대적으로 사용법이 간단하다.

옵션도 대부분 @Cacheable과 비슷하지만 다른 것들을 아래에 정리해두겠다.

  • allEntries
    • 캐시 이름에 해당하는 모든 항목을 삭제
    • 기본값: false
    • @CacheEvict(value = "myCache", allEntries = true)
  • beforeInvocation
    • 메서드 실행 전에 캐시를 삭제할지 여부를 결정
    • 기본값: false (메서드 실행 후 삭제)
    • @CacheEvict(beforeInvocation = true)
@CacheEvict(value = "myCache", allEntries = true)

@CacheEvict(beforeInvocation = true)

@CacheConfig

클래스 레벨에서 공통 캐시 설정을 지정할 때 사용한다.

CacheConfig도 사용법이 다양해서 다음에서 다루는 페이지에서 따로 설명하도록 하겠다.

@Caching

Caching은 앞서 설명했던 Cacheable, CachePut, CacheEvict를 묶어서 한번에 선언하는 것이다.

@Caching(
        cacheable = @Cacheable(key = "#id"),
        put = @CachePut(key = "#id"),
        evict = @CacheEvict(key = "#id")
)
public String complexCachingLogic(Long id, String value) {
    System.out.println("Performing complex caching logic for ID: " + id);
    return value;
}

 

@Cahcing을 처음 볼때 몇가지 질문이 생겼다.

1. @Cacheable과 @CachePut을 같이 쓰면 서로 기능이 다른데 어떻게 수행되나.

2. evict, put, cacheable은 어떤 순서로 실행되나.

 

우선 1번은 테스트 코드를 통해 확인해 볼 수 있다.

위 코드 예시처럼 cacheable과 put이 동일하게 설정됐을때 여러 번 호출 시

println 내용이 여러번 출력된다면 put만 수행된다는 것을 확인 할 수 있을 것이다.

@Test
void cachingTest() {
    System.out.println(baseCacheService.complexCachingLogic(2L, "Complex-Item-2"));
    System.out.println(baseCacheService.complexCachingLogic(2L, "Complex-Item-2"));
    System.out.println(baseCacheService.complexCachingLogic(2L, "Complex-Item-2"));
}

결과적으로는 모두 Performing complex caching logic for ID 가 출력되었다.

따라서 cacheable은 put과 사용시 동작하지 않는다.

그래서 같은 메서드에 @Cacheable과 @CachePut을 동시에 사용하지 않는게 좋다.

 

2번 evict는 메서드 실행전에 수행되기 때문에 put이나 cacheable이 수행되기 전에 수행된다.

따라서 beforeInvocation = true 옵션만 잘 생각해서 사용하면 된다.

728x90
반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
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 27 28 29 30 31
글 보관함
250x250