• 티스토리 홈
  • 프로필사진
    알쓸개잡
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
알쓸개잡
  • 프로필사진
    알쓸개잡
    • 분류 전체보기 (92)
      • 스프링부트 (52)
      • AWS (5)
      • 쿠버네티스 (7)
      • 자바 (19)
      • 인프라 (0)
      • ETC (8)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      • 반응형
      # 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일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바