赞
踩
Spring Cache官网:https://docs.spring.io/spring-framework/docs/5.2.11.RELEASE/spring-framework-reference/integration.html#cache
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
spring: # redis配置 redis: host: localhost port: 6379 pool: # 连接池最大连接数(使用负值表示没有限制) max-active: 8 # 连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1 # 连接池中的最大空闲连接 max-idle: 8 # 连接池中的最小空闲连接 min-idle: 0 # 连接超时时间(毫秒) timeout: 0 # cache配置 cache: type: redis
@EnableCaching
@SpringBootApplication
public class GulimallProductApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallProductApplication.class, args);
}
}
@Cacheable(value={"user"},key = "'userList'")
@GetMapping("/getUserList")
public List<User> getUserList(){
System.out.println("getUserList....");
//构造测试数据
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 18));
userList.add(new User("李四", 19));
userList.add(new User("王五", 20));
return userList;
}
@Cacheable 注解说明
缓存当前方法的返回的结果, 如果缓存中有,不调用方法,直接返回;如果缓存中没有,调用方法,最后将方法的结果放入缓存;
默认行为
缓存的value值,默认使用jdk序列化机制,将序列化的数据存到redis中;
key是默认生成的,如果不指定,默认user::SimpleKey [];可以通过key属性指定,接收一个SpEL表达式的值;
默认时间是 -1;可以在配置文件中配置
# 缓存存活时间,单位:毫秒
spring.cache.redis.time-to-live=360000
@Cacheable 属性说明
spring.cache.redis.key-prefix=CACHE_
, @Cacheable(value={"user"})
中的 value会失效!key = "#root.method.name"
表示用方法名作为key访问接口:localhost:8080/list
第一次打印 getUserList....
;查看redis缓存数据,redis中已经存入user的数据;
第二次直接走缓存,不调用方法,不打印;
缓存中的value默认是用jdk序列化,不方便的我们查看,修改成json序列化;
@EnableCaching //开启缓存启动类的注解从启动类移到这里 @Configuration public class MyCacheConfig { @Bean public RedisCacheConfiguration redisCacheConfiguration() { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); //key的序列化 string config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); //value的序列化 json config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); return config; } }
测试(同上),缓存中的value已经用json序列化,但过期时间变成 -1;也就是说配置文件中的值失效了!
[ "java.util.ArrayList", [ { "@class": "com.gulimall.product.entity.User", "name": "张三", "age": 18 }, { "@class": "com.gulimall.product.entity.User", "name": "李四", "age": 19 }, { "@class": "com.gulimall.product.entity.User", "name": "王五", "age": 20 } ] ]
原因:源码中缓存配置类CacheProperties
并没有放在容器中我们需要开启属性配置绑定功能:@EnableConfigurationProperties(CacheProperties.class)
,然后拿到配置文件的值赋值到属性中;可以参考源码RedisCacheConfiguration
类的createConfiguration
方法;
@EnableConfigurationProperties(CacheProperties.class) //开启属性配置绑定功能 @EnableCaching //开启缓存启动类的注解从启动类移到这里 @Configuration public class MyCacheConfig { @Bean public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // config = config.entryTtl(); //key的序列化 string config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); //value的序列化 json config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); CacheProperties.Redis redisProperties = cacheProperties.getRedis(); //将配置文件中所有的配置都生效 if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } if (redisProperties.getKeyPrefix() != null) { config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; } }
拿到容器中的CacheProperties
对象,可以像上面一样通过方法参数拿到,也可以通过注入一个属性拿到;
@Autowired
public CacheProperties cacheProperties;
@Cacheable
: 将数据保存到缓存;@CacheEvict
: 将数据从缓存删除;失效模式@CachePut
: 不影响方法执行更新缓存;双写模式@Caching
: 组合多个缓存操作;@CacheConfig
: 在类级别共享缓存的相同配置;添加到缓存
@Cacheable(value={"user"},key = "'userList'")
@GetMapping("/getUserList")
public List<User> getUserList(){
System.out.println("getUserList....");
//构造测试数据
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 18));
userList.add(new User("李四", 19));
userList.add(new User("王五", 20));
return userList;
}
删除缓存,【失效模式】
@CacheEvict(value={"user"},key = "'userList'")
@PostMapping("/addUser")
public User addUser(@RequestBody User user){
System.out.println("addUser....");
return user;
}
删除user分区的所有属性:@CacheEvict(value={"user"}, allEntries = true)
根据返回值更新缓存,【失效模式】
@CachePut(value={"user"}, key = "'userList1'")
@PutMapping("/updateUser")
public List<User> updateUser(){
System.out.println("updateUser....");
//构造测试数据
List<User> userList = new ArrayList<>();
userList.add(new User("1","张三", 18));
return userList;
}
组合多个缓存操作;
//同时删除user::userList1 和user::userList2 缓存
@Caching(evict = {
@CacheEvict(value={"user"},key = "'userList1'"),
@CacheEvict(value={"user"},key = "'userList2'")
})
@GetMapping("/caching")
public String caching(){
System.out.println("caching....");
return "caching ok";
}
读模式
@Cacheable(sync = true)
来解决击穿问题;读模式的3个问题spring Cache都考虑到了;
写模式:(缓存与数据库一致)
写模式spring Cache 没做特殊处理,根据特殊业务进行特殊处理!
总结
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。