SpringBoot- 캐시

소스 링크 : SpringBoot 캐싱 실습

1. 캐싱 소개

캐시는 고속 데이터 교환을 수행 할 수있는 스토리지를 의미하며이를 사용하여 데이터를보다 빠르게 운영하고 액세스 할 수 있습니다.
애플리케이션이 캐시에 추가되지 않은 경우 사용자는 데이터에 액세스
여기에 사진 설명 삽입
할 때 데이터베이스에 직접 액세스합니다 . 캐시가 추가되면 데이터베이스에 대한 부담을 효과적으로 줄일 수 있습니다
여기에 사진 설명 삽입
. 캐시의 장점 :

  • 캐시를 사용하면 데이터베이스에 대한 액세스를 피하고 데이터베이스 서버의 리소스를 절약 할 수 있습니다.
  • 성능은 더 빠르고 캐시는 메모리 수준의 서버이며 DB는 더 많은 비즈니스 논리 판단 및 디스크 작업을 포함하므로 캐시의 성능이 더 높습니다.

둘째, SpringBoot의 캐시

1. JSR107 캐시 사양

(Java 사양 요청, JSR) Java 사양 제안 Java Caching은 5 가지 핵심 인터페이스를 정의합니다.

  • CachingProvider : 여러 CacheManager의 생성, 구성, 획득, 관리 및 제어를 정의합니다. 애플리케이션은 런타임 중에 여러 CachingProvider에 액세스 할 수 있습니다.
  • CacheManager : CacheManager 의 컨텍스트에 존재하는 고유하게 명명 된 여러 캐시의 생성, 구성, 획득, 관리 및 제어를 정의합니다. CacheManager는 하나의 CachingProvider 만 소유합니다.
  • Cache : Map과 유사한 데이터 구조로 Key에 의해 인덱싱 된 값을 임시로 저장합니다. Cache는 하나의 CacheManager 만 소유합니다.
  • 항목 : 캐시에 저장된 키-값 쌍입니다.
  • 만료 : 캐시에 저장된 각 항목에는 정의 된 유효 기간이 있습니다.이 시간이 지나면 항목은 만료 된 상태가됩니다. 만료 된 항목은 액세스, 업데이트 또는 삭제할 수 없습니다. 캐시 유효 기간은 ExpiryPolicy를 통해 설정할 수 있습니다.

여기에 사진 설명 삽입

2. Spring의 캐시 추상화

Spring은 3.1 이후 다양한 캐싱 기술을 통합하기위한 인터페이스를 정의 org.springframework.cache.Cache
하고 org.springframework.cache.CacheManager있으며, JCache (JSR-107) 주석 사용을 지원하여 개발을 단순화합니다.

  • 캐시 인터페이스는 캐시의 다양한 작업 집합을 포함하는 캐시 구성 요소의 사양 정의입니다.
  • Spring은 RedisCache, EhCacheCache, ConcurrentMapCache 등과 같은 캐시 인터페이스에서 xxxCache의 다양한 구현을 제공합니다.
  • 캐시 함수가 필요한 메서드가 호출 될 때마다 Spring은 지정된 대상 메서드가 호출되었는지 여부를 확인하고, 해당 메서드가 호출 된 경우 캐시에서 직접 메서드 호출 결과를 가져옵니다. 메서드를 사용하고 결과를 캐시하여 사용자에게 반환합니다. 다음 호출은 캐시에서 직접 가져옵니다.

(1) 캐시의 공통 주석 및 개념 :
여기에 사진 설명 삽입
(2) @ Cacheable / @ CachePut / @ CacheEvict 기본 매개 변수

여기에 사진 설명 삽입
(3) SPEL 표현

  • 현재 호출 된 메서드의 이름 :#root.methodName
  • 현재 호출 된 메서드 :#root.method.name
  • 현재 호출중인 대상 개체 :#root.target
  • 현재 호출중인 대상 객체 클래스 :#root.targetClass
  • 현재 호출 된 메소드의 매개 변수 목록 :#root.args[0]
  • 현재 메서드 호출 (예 :)에 사용되는 캐시 목록 @Cacheable(value={"cache1","cache2"})에는 두 개의 캐시가 있습니다.#root.caches[0].name
  • 이름 매개 변수를 직접 할 수 있습니다 # 메소드 매개 변수 이름을 사용할 수 있습니다 #p0또는 #a0형태로, 0은 매개 변수의 인덱스를 나타냅니다 : #iban, #a0,#p0
  • 메서드 실행 후 반환 값 ( 'unless', 'put', 'evict', beforeInvocation = false와 같이 메서드 실행 후 판단이 유효한 경우에만) :#result

2. SpringBoot 캐시 사용

종속성 소개 :
여기에 사진 설명 삽입

구조 구축 :
여기에 사진 설명 삽입

(1) 캐싱 활성화 캐싱
을 활성화하려면 기본 런처 클래스에서 @EnableCaching을 구성합니다.
@MapperScan은 매퍼 인터페이스의 경로를 지정합니다.
여기에 사진 설명 삽입

(2) 캐시 운영 방법 : 추가, 수정, 삭제

@Cacheable : 쿼리

  • cacheNames / value : 캐시 구성 요소의 이름을 지정합니다.
  • 키 : 데이터를 캐시하는 데 사용되는 키로 지정할 수 있습니다. 기본값은 method 매개 변수의 값을 사용하는 것입니다.
  • condition : 지정된 조건이 충족되는 경우에만 캐시합니다 (예 : condition = "# id> 0").

@CachePut : 업데이트
는 데이터베이스의 특정 데이터를 수정하고 캐시를 업데이트합니다.

  • 값 : 캐시 이름
  • 키 : #id데이터베이스 데이터와 캐시의 데이터 를 동시에 업데이트하려면 업데이트 된 키가 기존 캐시의 키 ( )와 일치 하는지 확인하십시오.

@CacheEvict : 삭제

  • 키 : 지울 데이터를 지정합니다 (데이터베이스와 캐시의 데이터를 동시에 삭제하는 키에 해당).

서비스 계층에 캐시 추가, 캐시 수정, 캐시 삭제,

쓰기 서비스 :

//@CacheConfig(cacheNames="emp") //抽取缓存的公共配置
@Service
public class EmpService {
    
    
    @Autowired
    EmployeeMapper employeeMapper;

    @Cacheable(cacheNames = "emp",key="#id")
    public Employee getEmp(Integer id){
    
    
        System.out.println("查询第"+id+"个用户");
      return   employeeMapper.getEmployee(id);
    }

//先调用目标方法,再将结果缓存起来
    @CachePut(value = "emp",key = "#result.id")
    public Employee updateEmp(Employee employee){
    
    
        employeeMapper.updateEmp(employee);
        return employee;
    }


    @CacheEvict(value = "emp",key = "#id")
    public void deleteEmp(Integer id){
    
    
        employeeMapper.deleteEmployee(id);
    }

    @Caching(
           cacheable = {
    
    
                   @Cacheable(value = "emp", key = "#lastName")
           },
            put = {
    
    
                   @CachePut(value = "emp",key = "#result.id"),
                    @CachePut(value = "emp",key = "#result.email")
            }
    )
    public Employee getEmpByName(String lastName){
    
    
        return employeeMapper.getEmpByName(lastName);
    }
}

노트 :

  • @Caching : 구성 요소를 결합하여 여러 캐싱 전략을 설정할 수 있습니다.

여기에 사진 설명 삽입

  • @CacheConfig : 캐시 구성, 클래스에서 공용 캐시 구성을 지정할 수 있습니다.

컨트롤러 레이어를 작성합니다.

@RestController
public class EmpController {
    
    

    @Autowired
    EmpService empService;


    @GetMapping("/emp/{id}")
    public Object getEmp(@PathVariable("id") Integer id){
    
    
        return empService.getEmp(id);
    }


    @GetMapping("/emp")
    public Object updateEmp(Employee employee){
    
    
        empService.updateEmp(employee);
        return employee;
    }

    @GetMapping("/del/{id}")
    public void deleteEmp(@PathVariable("id") Integer id){
    
    
        empService.deleteEmp(id);
    }


    @GetMapping("/emp/name/{lastName}")
    public Object getEmpByName(@PathVariable("lastName") String lastName){
    
    
        return empService.getEmpByName(lastName);
    }
}

  • @Cacheable 캐시 쿼리 : 액세스 http://localhost:8080/emp/1: 첫 번째 호출 만 백그라운드에 인쇄되는 것으로 나타났습니다. "Query the first user", 쿼리 횟수에 관계없이 실제로 액세스 한 캐시입니다.
  • @CacheEvict 캐시 지우기 :에 액세스 http://localhost:8080/del/1하면 캐시 및 데이터베이스의 내용이 삭제되고 http://localhost:8080/emp/1다시 액세스 해도 데이터가 쿼리되지 않습니다. allEntries@CacheEvict에 속성 이 있는데 allEntries == true 일 때 @CacheEvict 메소드를 호출하면 모든 캐시가 삭제됩니다. beforeInvocation속성의 기본값은 false이고 캐시 지우기는 기본적으로 메서드가 실행 된 후에 실행됩니다.

셋, SpringBoot- 캐시 작동 방식

1. 캐시 자동 구성 클래스 CacheAutoConfiguration

캐시에 대한 자동 구성 클래스 :CacheAutoConfiguration

캐시를 사용할 때 많은 구성 클래스가로드되며이 중 구성 클래스 만 SimpleCacheConfiguration유효합니다.
여기에 사진 설명 삽입
여기에 사진 설명 삽입

2. @Cacheable 실행 프로세스 :

(1) 먼저 Cache 컴포넌트의 이름을
가져 오며 , 처음 실행시 해당 Cache가 존재하지 않으므로 ConcurrentMapCache를 생성해야합니다.

ConcurrentMapCacheManager :
여기에 사진 설명 삽입
(2) 키 값을 통해 캐시 얻기
캐시가 처음 실행되면 캐시가 존재하지 않으므로 캐시를 찾을 수 없습니다.

ConcurrentMapCache :
키를 통해 값을 얻습니다. 즉, ConcurrentMapCache는 기본 ConcurrentMap을 작동하여 캐싱 작업을 수행합니다.
여기에 사진 설명 삽입
참고 :
SimpleKeyGenerator는 기본적으로 키를 생성하는 데 사용됩니다.
여기에 사진 설명 삽입
(3) 캐시를 찾을 수없는 경우 대상 메서드를 호출합니다.

(4) 대상 메서드에서 반환 한 값을 캐시에 넣습니다.

요약 :
@Cacheable로 표시된 메소드를 실행하기 전에 캐시에이 데이터가 있는지 확인하십시오. 기본적으로 매개 변수의 값을 키로하여 캐시를 쿼리하십시오. 그렇지 않은 경우 메소드를 실행하고 결과를 은닉처.

넷째, Redis 캐시 미들웨어 통합

1. Redis 설치

(1) Docker 이미지 가속을 통해 Redis를 가져옵니다.

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors에 로그인 하고 컨테이너 미러링 서비스를 열고 Alibaba Cloud의 이미지 가속 주소
여기에 사진 설명 삽입
를 가져옵니다. 가져온 후 다음 명령을 사용하여 redis를 가져옵니다. :

docker pull 阿里云专属地址/library/redis

例如:https://ezgxiyys.mirror.aliyuncs.com
docker pull ezaaaets.mirror.aliyuncs.com/library/redis

(2) Redis 시작

docker run -d -p 6379:6379 --name myredis
ezgxiyys.mirror.aliyuncs.com/library/redis(镜像名)

2. Redis 통합

(1) 의존성 도입 :

  <dependency>
       <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>

종속성을 가져온 후 RedisAutoConfiguration 자동 구성 클래스가 자동으로 적용됩니다.
여기에 사진 설명 삽입

  • RedisAutoConfiguration은 RedisOperations가 존재하는 경우에만 적용됩니다 (Spring Data Redis가 프로젝트에 도입 됨).
  • 두 개의 Bean이 제공되며 RedisTemplate의 두 가지 제네릭 유형은 모두 Object이므로 저장된 키와 값이 객체가 될 수 있습니다. 일반적으로 String 유형의 데이터가 많기 때문에 두 개의 제네릭 유형이 모두 String 인 StringRedisTemplate은 별도로 추출되므로 StringRedisTemplate의 키와 값은 문자열 만 될 수 있습니다.

(2) 기본 작업
5 가지 기본 데이터 유형이 작동합니다.
opsForValue : string
opsForList : list
opsForSet : set
opsForHash : hash
opsForZSet : ordered set

(3) 기본 직렬화 메커니즘
Redis는 기본적으로 Jdk의 직렬화 방법을 사용하여 객체를 저장합니다.
여기에 사진 설명 삽입
저장된 객체 클래스는 Serializable 인터페이스를 구현해야하며 저장된 결과는 다음과 같습니다.
여기에 사진 설명 삽입

(4) 사용자 정의 직렬화 메커니즘
사용자 정의 직렬화 메커니즘 :
여기에 사진 설명 삽입
테스트 :
여기에 사진 설명 삽입

여기에 사진 설명 삽입
(5) 커스텀 CacheManager

Redis가 도입되기 전에 CacheManager는 기본적으로 SimpleCacheConfiguration을 사용하여 생성되었습니다. Redis 도입 후 RedisCacheConfiguration이 적용되며 RedisCacheManager가 컨테이너에 미리 도입되어 SimpleCacheConfiguration이 무효화됩니다.
여기에 사진 설명 삽입
RedisCacheManager는 RedisCache를 캐시 구성 요소로 생성하고 RedisCache는 Redis를 운영하여 데이터를 캐시합니다.

이때 다시 방문 http://localhost:8080/emp/1하면 Redis를 통해 캐시 할 수 있습니다.
여기에 사진 설명 삽입

RedisCacheManager는 기본적으로 jdk의 직렬화 방법을 사용합니다
여기에 사진 설명 삽입
. RedisCacheManager를 사용자 지정하여 캐시 직렬화를 실현할 수 있습니다.
여기에 사진 설명 삽입
전체 코드는 다음과 같습니다.

@Configuration
public class MyredisConfig {
    
    

    @Bean
    public RedisTemplate<Object, Employee> myredisTemplate(RedisConnectionFactory redisConnectionFactory) {
    
    
        RedisTemplate<Object, Employee> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Employee>(Employee.class));
        return template;
    }

    @Bean
    RedisCacheManager cacheManager(RedisConnectionFactory factory) {
    
    
        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .disableCachingNullValues()
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                 .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();
    }
}

노트 :

  • redis를 캐시 미들웨어로 사용하여 데이터를 처음 쿼리하면 엔티티 클래스가 직렬화되어 캐시에 저장됩니다. 데이터가 두 번째 쿼리되면 캐시에서 직렬화 된 데이터를 직접 검색합니다. , 그런 다음 역 직렬화하십시오. 캐시에있는 직렬화 된 데이터는 직관적이지 않습니다. json과 같은 데이터 형식을 보려면 직렬화 규칙을 사용자 정의해야합니다.
  • SpringBoot1.xx와 2.XX 사이의 변경 사항은 비교적 큽니다. 자세한 내용은 블로그를 참조하십시오 : https://blog.csdn.net/Pique1896/article/details/106953841/

추천

출처blog.csdn.net/glpghz/article/details/111559851