结果缓存

对于需要被大量访问的数据,Spring提供了缓存解决方案。因为实体层面存在数据关联,因此我们采用在Service层缓存DTO的方式使用缓存。

只有高频的、重复的查询才有缓存的需求,比如:根据航班ID查询航班。一般系统不推荐使用结果缓存。

依赖

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

配置

开发者需要在入口类上配置@EnableCaching启用缓存的支持。

DemoApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableSwagger2
@EnableDiscoveryClient
@EnableCaching
public class DemoApplication {

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

示例

FooService.java
package com.example.demo.service;

import com.example.demo.*;
import com.taocares.commons.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
@CacheConfig(cacheNames = "foo-cache")
public class FooService {

    @Autowired
    private FooRepository fooRepository;

    @Cacheable
    public Optional<FooDto> findById(Long fooId) {
        Optional<Foo> foo = fooRepository.findById(fooId);
        if (foo.isPresent()) {
            return Optional.of(BeanUtils.copyProperties(foo.get(), FooDto.class));
        } else {
            return Optional.empty();
        }
    }

    @CachePut(key = "#result.id")
    public FooDto updateFoo(FooDto fooDto) {
        Foo foo = BeanUtils.copyProperties(fooDto, Foo.class);
        fooRepository.save(foo);
        return BeanUtils.copyProperties(foo, FooDto.class);
    }
    
    @CacheEvict(allEntries = true)
    public void batchUpdate(List<FooDto> fooDtos) {
        // do something ...
    }
}

对于Optional对象,缓存的内容为实际数据,而非Optional对象本身。

@CacheConfig

全局的配置,一般用于指定cacheManagercacheNames,简化缓存配置。

@Cacheable

根据唯一标识查询数据的方法常用此注解。方法执行之后,会将返回值放入缓存中。默认情况下,缓存的key即为方法的参数。

使用@Cacheable注解的方法,如果key被找到,则不执行方法体。

@CachePut

修改数据的方法常用此注解,更新缓存中的数据。此例中,key = "#result.id"表示从返回值中获取id属性作为key。

缓存的数据为方法的返回值,因此方法必须返回DTO。

key使用SpEL(Spring Expression Language)定义,具体语法请参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions

@CacheEvict

批量更新数据或者删除数据的方法常用此注解,删除缓存中对应的记录。此例中,allEntries = true表示所有缓存的数据都被清空。

参考文档

关于Spring Cache的更多内容请参考官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache

Last updated