• 티스토리 홈
  • 프로필사진
    알쓸개잡
  • 태그
  • 블로그 관리
  • 글 작성
알쓸개잡
  • 프로필사진
    알쓸개잡
    • 분류 전체보기 (98)
      • 스프링부트 (57)
      • AWS (5)
      • 쿠버네티스 (7)
      • 자바 (19)
      • 인프라 (1)
      • ETC (9)
  • 리얼포스 Realforce R3S 키보드 R3SD13 토프레 무점접키보드, 기본, 기본, 텐키리스
    반응형
# Home
# 공지사항
#
# 태그
# 검색결과
# 방명록
  • Spring Cache 주요 어노테이션
    2024년 05월 20일
    • 알쓸개잡
    • 작성자
    • 2024.05.20.:10

    Spring Cache는 캐싱 기능을 통해 애플리케이션 성능을 향상할 수 있는 강력한 도구를 제공한다. 이번 포스팅에서는 Spring Cache 추상화를 통해서 제공되는 주요 어노테이션과 기능에 대해서 정리하고자 한다.

     

    @Cacheable

    @Cacheable 어노테이션은 메서드 결과를 캐시에 저장하고, 이 후 같은 파라미터로 메서드가 호출될 경우 캐시 된 결과를 반환한다. 이는 주로 읽기 작업에 사용된다.

    속성

    • value 또는 cacheNames: 캐시 이름을 지정한다.
    • key: 캐시에 저장될 엔트리 키를 지정한다. SpEL(Spring Expression Language)를 사용하여 동적으로 설정할 수 있다.
    • condition: 캐시를 적용할 조건을 SpEL로 지정한다.
    • unless: 캐시에 저장하지 않을 조건을 SpEL로 지정한다.
    • sync: 여러 스레드가 동시에 캐시에 접근할 때 동기화할지 여부를 지정한다.
    @Cacheable(value = "users", key = "#userId")
    public User getUserById(Long userId) {
        // DB에서 사용자 정보를 조회하는 로직
        return userRepository.findById(userId).orElse(null);
    }
    • users 캐시에 userId 키가 존재하지 않는 경우
      • users 이름의 캐시에 userId 인자로 전달되는 값을 엔트리 키로 하여 메서드의 리턴 값을 users 캐시에 저장한다.
    • users 캐시에 userId 키가 존재하는 경우
      • users 캐시로 부터 결과를 반환한다. 메서드 내의 로직은 실행되지 않는다.

    즉, @Cacheable은 메서드 실행 전에 캐시를 확인한다.

     

    @CachePut

    @CachePut 어노테이션은 메서드를 실행하고 그 결과를 캐시에 저장한다. 메서드 호출 시마다 캐시를 업데이트하며, 주로 쓰기 작업에 사용된다.

    속성

    • value 또는 cacheNames: 캐시 이름을 지정한다.
    • key: 캐시 키를 지정한다. SpEL을 사용하여 동적으로 설정할 수 있다.
    • condition: 캐시를 적용할 조건을 SpEL로 지정한다.
    • unless: 캐시에 저장하지 않을 조건을 SpEL로 지정한다.
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        // 사용자 정보를 업데이트하는 로직
        return userRepository.save(user);
    }

    위 코드에서 메서드 호출 결과를 users 캐시의 user.id를 키로 갖는 엔트리에 업데이트한다.

    만약 users 캐시에 user.id를 키로 갖는 엔트리가 없다면 추가된다.

     

    @CachePut 어노테이션은 항상 메서드를 실행하고 그 결과를 캐시에 갱신한다.

    캐시에 데이터가 없는 경우에만 메서드 내의 로직이 실행되는 @Cacheable 어노테이션과 주요 차이점 중 하나다.

    데이터베이스 업데이트나 새로운 데이터 생성을 처리할 때 유용하며, 메서드가 호출될 때마다 캐시를 최신 상태로 유지할 수 있다.

    @CachePut 어노테이션을 적절히 사용하여 캐시 일관성을 유지하고 성능을 최적화할 수 있다.

     

    @CacheEvict

    @CacheEvict 어노테이션은 캐시에서 하나 이상의 엔트리를 제거한다. 메서드가 실행된 후 지정된 키 또는 캐시 이름의 엔트리를 제거한다.

     

    속성

    • value 또는 cacheNames: 캐시 이름을 지정한다.
    • key: 제거할 캐시 키를 지정한다. SpEL을 사용하여 동적으로 설정할 수 있다.
    • allEntries: 캐시의 모든 엔트리를 제거할지 여부를 설정한다. (기본값: false)
    • beforeInvocation: 메서드 호출 전에 캐시를 비울지 여부를 지정한다. (기본값: false)
    @CacheEvict(value = "users", key = "#userId")
    public void deleteUserById(Long userId) {
        // 사용자 정보를 삭제하는 로직
        userRepository.deleteById(userId);
    }

    위 코드는 userId 에 해당하는 식별자를 갖는 데이터를 DB에서 삭제 후에 users 캐시에 저장된 userId를 키로 갖는 엔트리도 제거한다.

    • beforeInvocation 속성
      • true로 지정된 경우 메서드 실행 이전에 캐시로부터 데이터를 삭제하기 때문에 메서드 실행 성공 여부와 관계없이 캐시에서 데이터가 삭제된다.
      • false로 지정된 경우 메서드 실행 이후에 캐시로부터 데이터를 삭제하기 때문에 만약 메서드 실행 도중 예외가 발생한 경우 캐시에서 데이터가 삭제되지 않는다. 메서드 실행이 정상적으로 이루어진 경우에만 캐시에서 데이터가 삭제된다.

     

    @Caching

    @Caching 어노테이션은 여러 캐시 작업을 조합할 수 있도록 한다. @Cacheable, @CachePut, @CacheEvict을 조합하여 복잡한 캐싱 규칙을 정의할 수 있다.

    속성

    • cacheable: @Cacheable 어노테이션 배열
    • put: @CachePut 어노테이션 배열
    • evict: @CacheEvict 어노테이션 배열
    @Caching(
        put = { @CachePut(value = "users", key = "#user.id") },
        evict = { @CacheEvict(value = "userIds", key = "#user.username") }
    )
    public User saveUser(User user) {
        // 사용자 정보를 저장하는 로직
        return userRepository.save(user);
    }

    saveUser() 메서드가 호출될 때 @Caching 어노테이션에 의해서 다음 두 가지 캐시 관련 작업이 수행된다.

    • @CachePut: user 캐시에 user.id를 키로 하는 엔트리에 메서드의 결과인 User 인스턴스를 저장한다.
    • @CacheEvict: userIds 캐시에 user.username을 키로 하는 엔트리를 제거한다.
    @Caching 어노테이션에 지정된 여러 캐시 작업은 지정된 순서를 보장하지 않는다.
    만약 캐시 관련 작업에 순서가 중요한 경우에는 @Caching 어노테이션에 여러 캐시 작업을 속성으로 지정하는 대신에 명시적으로 캐시 작업을 분리하여 메서드를 정의하는 것이 좋다.

     

    @Caching 어노테이션에서 동일한 키에 대해 @Cacheable과 @CachePut 속성이 함께 지정된 경우 어떻게 동작할까?

    @Caching(
        cacheable = { @Cacheable(value = "users", key = "#user.id") },
        put = { @CachePut(value = "users", key = "#user.id") }
    )
    public User saveUser(User user) {
        // 사용자 정보를 저장하는 로직
        return userRepository.save(user);
    }

    위와 같이 @Caching 어노테이션이 지정된 경우 @CachePut 어노테이션의 특성 때문에 메서드는 항상 실행되고 반환된 결과가 캐시에 저장된다.

    동작과정은 다음과 같다.

    1. saveUser() 메서드 호출

    2. @Cacheable

    • @Cacheable은 메서드 내의 로직이 실행되기 전에 캐시를 확인한다.
    • 하지만 @CachePut이 존재하므로 @Cacheable의 캐시 확인은 실제로 영향을 미치지 않는다.

    3. 메서드 실행: userRepository.save() 가 호출된다.

    4. @CachePut

    • saveUser() 메서드 호출 결과 반환된 User 인스턴스가 users 캐시에 user.id 키로 엔트리에 저장된다.

    다음 코드를 살펴보자.

    @Caching(
        cacheable = { @Cacheable(value = "users", key = "#userId") },
        put = { @CachePut(value = "users", key = "#userId") }
    )
    public User getUserById(Long userId) {
        return userRepository.findById(userId).orElse(null);
    }

    getUserById() 메서드를 호출 했을 때 동작 과정은 다음과 같다.

    1. getUserById() 메서드 호출

    2. @Cacheable

    • users 캐시에서 userId를 키로 저장된 값을 조회한다.
    • 캐시에 해당 키가 존재하면 캐시된 값이 반환되고, userRepository.findById(userId).orElse(null)는 실행되지 않는다.
    • 캐시에 해당 키가 없으면 userRepository.findById(userId).orElse(null)는 실행된다.

    3. @CachePut

    • @CachePut에 의해서 userRepository.findById(userId).orElse(null)는 항상 실행된다.
    • userRepository.findById(userId).orElse(null) 실행 결과를 캐시에 저장한다.

    결과적으로 위 두가지 케이스 모두 캐시 조회와 캐시 갱신이 동시에 발생하기 때문에 @Cacheable의 효율성이 떨어진다.

    @Caching 어노테이션에서 @Cacheable과 함께 @CachePut 혹은 @CacheEvict을 사용하는 것은 항상 메서드의 실행을 발생시키기 때문이다.

    일반적으로 @Caching 어노테이션 내에서 조합하여 캐시 동작을 정의 하는 것보다 각각 캐시 기능을 정의하는 것이 바람직하다.

     

    @CacheConfig

    @CacheConfig 어노테이션은 클래스 레벨에서 캐시 설정을 공통으로 지정할 수 있도록 한다. 클래스 내 모든 캐시 어노테이션에 적용된다.

     

    속성

    • cacheNames: 캐시 이름을 지정한다.
    • keyGenerator: 키 생성기를 지정한다.
    • cacheManager: 캐시 매니저를 지정한다.
    • cacheResolver: 캐시 리졸버를 지정한다.
    @CacheConfig(cacheNames = "users")
    public class UserService {
    
        @Cacheable(key = "#userId")
        public User getUserById(Long userId) {
            // DB에서 사용자 정보를 조회하는 로직
            return userRepository.findById(userId).orElse(null);
        }
    
        @CachePut(key = "#user.id")
        public User updateUser(User user) {
            // 사용자 정보를 업데이트하는 로직
            return userRepository.save(user);
        }
    
        @CacheEvict(key = "#userId")
        public void deleteUserById(Long userId) {
            // 사용자 정보를 삭제하는 로직
            userRepository.deleteById(userId);
        }
    }

    UserService 내에 정의된 각 메서드에서 사용하는 캐시는 users 이름의 캐시를 사용한다.

     

    끝.

    저작자표시 비영리 변경금지 (새창열림)

    '스프링부트' 카테고리의 다른 글

    logback을 이용한 spring boot 애플리케이션 syslog 전송하기  (0) 2024.06.07
    Spring Data Redis - cache 기능 사용하기  (0) 2024.06.02
    Spring 이벤트 시스템을 이용한 실시간 데이터 변경 감지 및 처리  (0) 2024.05.17
    Spring Data Redis - Redis Repository 사용  (0) 2024.05.12
    Spring Data Redis - RedisTemplate의 HashOperations  (0) 2024.04.29
    다음글
    다음 글이 없습니다.
    이전글
    이전 글이 없습니다.
    댓글
조회된 결과가 없습니다.
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
목차
표시할 목차가 없습니다.
    • 안녕하세요
    • 감사해요
    • 잘있어요

    티스토리툴바