티스토리 뷰
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 옵션만 잘 생각해서 사용하면 된다.
'Back End > Spring' 카테고리의 다른 글
Spring Caching으로 성능 올리기 - (3) cache config(ehcache, redis, caffeine) (0) | 2025.01.11 |
---|---|
Spring Caching으로 성능 올리기 - (2) key generator (0) | 2025.01.11 |
[Test] Spring boot, Junit, Testcontainers를 이용한 테스트 환경 만들기 (0) | 2024.04.11 |
[Spring Data] Spring Data MongoDB - insert() vs save() (0) | 2024.04.06 |
[Spring] Logback으로 Spring 애플리케이션 Logging 하기 (2) | 2024.03.05 |
- Total
- Today
- Yesterday
- API
- frontend
- feign client
- spring boot
- KAFKA
- Firebase
- consumer
- Producer
- Linux
- backend
- OS
- Container
- apache kafka
- 리액트
- NextJS
- centos
- React
- 프론트엔드
- JPA
- zookeeper
- cs
- Data Engineering
- caching
- Java
- rhel
- K8S
- broker
- spring
- Front
- apache
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |