SpringCache的简介

缓存,就是将数据从数据库等数据来源获取数据,将数据缓存在内存或其他设备如Redis中,为了二次查询能够快速高效的响应结果.

Spring Cache是3.1开始提供, 通过注解的形式,对于整合业务代码友好.

Spring Cache特点:

提供Cache通用入口 ,方便多种实现切换缓存源,如Redis,Guava Cache等
支持事务, 即事务回滚时,缓存同时自动回滚

Cache-redis环境搭建

1.依赖配置
<!-- Cache基础依赖 -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 使用  redis  -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- jackson默认不支持java8的时间类型,需要添加一个时间模块 -->
<dependency>
	<groupId>com.fasterxml.jackson.datatype</groupId>
	<artifactId>jackson-datatype-jsr310</artifactId>
	<version>2.13.0</version>
</dependency>
2.application配置
#redis
  redis:
    host: 43.139.54.197
    port: 6370
    password: '123456'
    database: 0
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 1000ms #连接等待时间
      debug: true

Cache的注解

@EnableCaching

使用场景:在启动类注解@EnableCaching开启缓存 

@SpringBootApplication
@EnableCaching  //开启缓存
public class DemoApplication{

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

使用场景: 查询方法接口

该注解会把方法的返回值缓存下来, 下一次调用方法时, 先查询缓存中是否存在,存在则直接返回,不存在,则查询数据返回,并将数据缓存.

// 先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中
    @Cacheable(value = "user", key = "#id")
    public User select(String id) {
        List<User> users = userMapper.selectAll();
        for (User user : users) {
            if (user.getId().equals(id)) {
                return user;
            }
        }
        return null;
    }

1.注解属性:

注解属性

作用

cacheNames

缓存key前缀名字,设置缓存组件

key

缓存key后缀

condition

SpringEL表达式,结果为true,缓存数据到redis。结果为false,不缓存数据到redis

unless

SpringEL表达式,结果为false,缓存数据到redis。结果为true,不缓存数据到redis

2.SpEL上下文数据

属性名称

描述

示例

methodName

当前方法名

#root.methodName

method

当前方法

#root.method.name

target

当前被调用的对象

#root.target

targetClass

当前被调用的对象的class

#root.targetClass

args

当前方法参数组成的数组

#root.args[0]

caches

当前被调用的方法使用的Cache

#root.caches[0].name

@Cacheput

使用场景: 新增或修改方法

该注解会把方法的返回值Put到缓存中, 供其他查询使用,如果有同一缓存则覆盖.

// 查询数据库,将返回结果放到缓存
    @CachePut(value = "user", key = "#user.id")
    public User save(User user) {
        userMapper.insert(user);
        return user;
    }
@CacheEvict

使用场景: 删除或修改方法

该注解会清空指定缓存.

// 移除对应的缓存
    @CacheEvict(value = "user", key = "#user.id")
    public User update(User user) {
        userMapper.updateByPrimaryKey(user);
        return user;
    }
@Caching

使用场景: 同时操作多个缓存

该注解是一个组合缓存,可以同时添加几个不同的注解,供不同的应用场景使用.如一个接口,可能同时操作多个缓存,且缓存的处理状态都不一样.

@Caching(
    cacheable = {
        @Cacheable(value = "user",keyGenerator = "xdclassKeyGenerator")
	},
	put = {
        @CachePut(value = "user",key = "#id"),
		@CachePut(value = "user",key = "'stock:'+#id")
	}
)
@CacheConfig

该注解用于配置该类中用的一些共用的缓存配置

@CacheConfig(cacheNames = "cache:prefix")

Redis序列化配置类和Cache缓存配置类

@Configuration
public class RedisConfig {

    private static StringRedisSerializer stringRedisSerializer;

    private static Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer;

    static {
        //定义string类型序列化对象
        stringRedisSerializer = new StringRedisSerializer();
        //定义Jackson类型序列化对象
        jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        //LocalDateTime序列化异常
        om.registerModule(new JavaTimeModule());
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL
                , JsonTypeInfo.As.WRAPPER_ARRAY);
        jackson2JsonRedisSerializer.setObjectMapper(om);
    }

    @Bean //Redis序列化配置
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //配置连接工程
        template.setConnectionFactory(factory);
        //redis key序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //redis value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hashmap  key序列化
        template.setHashKeySerializer(stringRedisSerializer);
        //hashmap value序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }
    
	//Cache配置
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                //过期时间
                .entryTtl(Duration.ofSeconds(600))
                //缓存key
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
                //缓存组件value
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                //value不为空
                .disableCachingNullValues()
                .computePrefixWith(cacheName -> cacheName + ":");

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

Cache的自定义Key策略组件配置

1.配置
@Component("selfKeyGenerate")
public class SelfKeyGenerate implements KeyGenerator {



    public Object generate(Object target, Method method, Object... params) {
        if (params.length == 0) {
            return SimpleKey.EMPTY;
        }
        Object param = params[0];
        // 参数为map自定义key=类名+方法名+map的key-value值
        if (param instanceof Map) {
            StringBuilder builder = new StringBuilder();
//             分隔符
            String sp = ".";

            builder.append(target.getClass().getSimpleName()).append(sp);
            builder.append(method.getName()).append(sp);
            Map<String, Object> map = (Map<String, Object>) param;
            if (map.isEmpty()) {
                return builder.toString();
            }
            for (String key : map.keySet()) {
                builder.append(key).append("-").append(map.get(key)).append(sp);
            }
//            builder.append(IdUtil.randomUUID());
            return builder.toString();
        }
        return new SimpleKey(params);
    }

}
2.使用
@Cacheable(cacheNames = "perCenter",keyGenerator = "selfKeyGenerate")
    public R PersonalCenter(HttpServletRequest request){
        return null;
    }