back end/java

spring boot에서 Cache 사용하는 방법

노루아부지 2025. 4. 9. 10:52
반응형

 

개발 환경

 

 

 

개발 환경 버전
java 17
Spring Boot 3.4.4
build Gradle
IDE IntelliJ IDEA 2022.3
DB H2
ORM JPA

 

 


Cache Annotation

 

🗂️ @Cacheable

  • 목적: 메서드 실행 결과를 캐시에 저장하고, 다음 호출 시 캐시된 결과를 반환합니다.
  • 작동 방식:
    1. 지정된 캐시에 해당 키가 존재하면 메서드를 실행하지 않고 캐시된 값 반환
    2. 캐시에 값이 없으면 메서드 실행 후 결과를 캐시에 저장
  • 주로 사용되는 상황: 자주 조회되지만 자주 변경되지 않는 데이터
@Cacheable(value = "userCache", key = "#userId")
public User getUser(String userId) {
  // select user
}
 

🔄 @CachePut

  • 목적: 메서드를 실행하고 항상 결과를 캐시에 저장합니다.
  • 차이점: @Cacheable은 캐시가 있으면 메서드를 실행하지 않지만, @CachePut은 무조건 실행 후 결과를 저장합니다.
  • 주로 사용되는 상황: 데이터 수정 혹은 갱신 시, 캐시를 최신 상태로 유지하고 싶을 때
@CachePut(value = "userCache", key = "#user.userId")
public User updateUser(User user) {
  // update user
}
 
 

🗑️ @CacheEvict

  • 목적: 캐시에 저장된 데이터를 삭제합니다.
  • 옵션:
    • key: 특정 키만 삭제
    • allEntries = true: 해당 캐시에 저장된 모든 데이터 삭제
  • 주로 사용되는 상황: 데이터 삭제 시 캐시도 함께 제거해야 할 때
@CacheEvict(value = "userCache", key = "#userId")
public void deleteUser(String userId) {
  // delete user
}

@CacheEvict(value = "userCache", allEntries = true)
public void reset() {
  // delete all user
}

 

 

⚙️ @CacheConfig

  • 목적: 클래스 단위로 공통 캐시 설정을 적용할 수 있습니다.
  • 설정 예시: cacheNames, keyGenerator, cacheManager 등
  • 효율성: 각 메서드에 반복적으로 설정하는 것을 줄일 수 있음
@CacheConfig(cacheNames = "userCache")
public class UserService {
  @Cacheable(key = "#userId")
  public User getUser(Long userId) {
    // ...
  }
}
 

📦 @Caching

  • 목적: 하나의 메서드에 여러 개의 캐시 관련 어노테이션을 함께 사용할 수 있도록 해줍니다.
  • 사용 예시: @Cacheable, @CachePut, @CacheEvict 등을 복합적으로 사용해야 할 경우
@Caching(
  evict = {
    @CacheEvict(value = "userCache", key = "#user.id"),
    @CacheEvict(value = "orderCache", key = "#user.id")
  }
)
public void deleteUser(User user) {
  // ...
}

 

 

 


Cache 사용 설정

 

😊 Dependency 추가

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

 

 

😊 @EnableCaching 추가

SpringBootApplication에 아래와 같이 @EnableCaching 추가

@EnableCaching
@SpringBootApplication
public class CacheApplication {

	public static void main(String[] args) {
		SpringApplication.run(CacheApplication.class, args);
	}

}

 

 

 


Code

 

📄 Entity

@Entity
@Getter
@Setter
@Table(name = "t_user")
public class User {
  @Id
  private String userId;
  private String name;
  private int age;
}

 

 

📄 Controller

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/users")
public class UserController {
  public final UserService service;

  @GetMapping("/{id}")
  public Optional<User> getUser(@PathVariable String id) {
    return service.getUser(id);
  }

  @PostMapping
  public User insertUser(@RequestBody User user) {
    return service.insertUser(user);
  }

  @PutMapping
  public User updateUser(@RequestBody User user) {
    return service.updateUser(user);
  }

  @DeleteMapping("/{id}")
  public void deleteUser(@PathVariable String id) {
    service.deleteUser(id);
  }
}

 

 

📄 Service

@Service
@RequiredArgsConstructor
@Slf4j
@CacheConfig(cacheNames = "userCache")
public class UserService {

  private final UserRepository repository;

  @Cacheable(key = "#userId")
  public User getUser(String userId) {
    log.info("DB 조회: {}", userId);
    return repository.findById(userId)
        .orElseThrow(() -> new IllegalArgumentException("사용자가 존재하지 않습니다."));
  }

  @CachePut(key = "#user.userId")
  public User insertUser(User user) {
    if (repository.existsById(user.getUserId())) {
      throw new IllegalArgumentException("이미 존재하는 사용자입니다.");
    }
    return repository.save(user);
  }

  @CachePut(key = "#user.userId")
  public User updateUser(User user) {
    if (!repository.existsById(user.getUserId())) {
      throw new IllegalArgumentException("사용자가 존재하지 않습니다.");
    }
    return repository.save(user);
  }

  @CacheEvict(key = "#userId")
  public void deleteUser(String userId) {
    repository.deleteById(userId);
  }

  @CacheEvict(allEntries = true)
  public void resetCache() {
    log.info("Cache reset");
  }
}

 

 

 


Test

 

intellij에서 아래와 같이 테스트 진행

 

🚀 generated-requests.http

# 사용자 생성
POST http://localhost:8080/api/users
Content-Type: application/json

{
  "userId": "u001",
  "name": "홍길동",
  "age": 25
}

###
# 사용자 조회 - DB 조회되지 않아야 함
GET http://localhost:8080/api/users/u001

###
# 사용자 수정
PUT http://localhost:8080/api/users
Content-Type: application/json

{
  "userId": "u001",
  "name": "임꺽정",
  "age": 22
}

###
# 사용자 다시 조회 - DB 조회되지 않아야 함
GET http://localhost:8080/api/users/u001

###
# 사용자 삭제
DELETE http://localhost:8080/api/users/u001

###
# 사용자 조회 - DB 조회되어야 함
GET http://localhost:8080/api/users/u001

###
# 초기화
# GET http://localhost:8080/api/users/reset

 

 

📋 API 실행 결과

 

📋 Console

 

 

728x90
반응형
loading