境外网站建设,wordpress外链转跳页面,免费网站建设协议,网站每月流量概述
使用 Spring Cache 可以极大的简化我们对数据的缓存#xff0c;并且它封装了多种缓存#xff0c;本文基于 redis 来说明。 基本使用
1、所需依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-…概述
使用 Spring Cache 可以极大的简化我们对数据的缓存并且它封装了多种缓存本文基于 redis 来说明。 基本使用
1、所需依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId
/dependency
2、配置文件
spring:# redis连接信息redis:host: 192.168.56.10port: 6379cache:# 指定使用的缓存类型type: redis# 过期时间redis:time-to-live: 3600000# 是否开启前缀默认为trueuse-key-prefix: true# 键的前缀如果不配置默认就是缓存名cacheNameskey-prefix: CACHE_# 是否缓存空置防止缓存穿透默认为truecache-null-values: true
3、Spring Cache 提供的注解如下使用方法参见官方文档通过这些注解我们可以方便的操作缓存数据。
Cacheable触发缓存写入的操作CacheEvict触发缓存删除的操作CachePut更新缓存而不会影响方法的执行Caching重新组合要应用于一个方法的多个缓存操作即对一个方法添加多个缓存操作CacheConfig在类级别共享一些与缓存有关的常见设置
例如如果需要对返回结果进行缓存直接在方法上标注 Cacheable 注解在主配置类上需要标注上 EnableCaching
Cacheable(cacheNames userList) //指定缓存的名字便于区分不同缓存
public ListUser getUserList() {...
}
4、redis 默认使用 jdk 序列化需要我们配置序列化机制自定义一个配置类否则存入的数据显示乱码
EnableCaching //开启缓存
Configuration
public class MyCacheConfig {Beanpublic RedisCacheConfiguration redisCacheConfiguration(){RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig();//指定键和值的序列化机制config config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));config config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));return config;}
}
5、使用以上配置后虽然乱码的问题解决了但配置文件又不生效了比如过期时间等这是因为在初始化时会判断用户是否自定义了配置文件如果自定义了原来的就不会生效源码如下
private org.springframework.data.redis.cache.RedisCacheConfigurationdetermineConfiguration(ClassLoader classLoader) {//如果配置了就返回自定义的配置if (this.redisCacheConfiguration ! null) {return this.redisCacheConfiguration;}//没配置使用默认的配置Redis redisProperties this.cacheProperties.getRedis();org.springframework.data.redis.cache.RedisCacheConfiguration config org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig();config config.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));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;
}
6、所以我们也需要手动获取 ttl、prefix 等属性直接仿照源码就行将配置类修改为如下
EnableCaching //开启缓存
Configuration
EnableConfigurationProperties(CacheProperties.class) //缓存的所有配置属性都在这个类里
public class MyCacheConfig {Beanpublic RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {//获取默认配置RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig();//指定键和值的序列化机制config config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));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;}
}
原理分析
在 Spring 中 CacheManager 负责创建管理 CacheCache 负责缓存的读写因此使用 redis 作为缓存对应的就有 RedisCacheManager 和 RedisCache。
打开 RedisCache 源码我们需要注意这两个方法
1、读取数据未加锁
Override
protected Object lookup(Object key) {byte[] value cacheWriter.get(name, createAndConvertCacheKey(key));if (value null) {return null;}return deserializeCacheValue(value);
}
2、读取数据加锁这是 RedisCache 中唯一一个同步方法
Override
public synchronized T T get(Object key, CallableT valueLoader) {ValueWrapper result get(key);if (result ! null) {return (T) result.get();}T value valueFromLoader(key, valueLoader);put(key, value);return value;
}
通过打断点的方式可以知道 RedisCache 默认调用的是 lookup()因此不能应对缓存击穿如果有相关需求可以这样配置Cacheable(sync true)开启同步模式此配置只在 Cacheable 中才有。
总结
Spring Cache 对于读模式下缓存失效的解决方案
缓存穿透cache-null-values: true允许写入空值缓存击穿Cacheable(sync true)加锁缓存雪崩time-to-live:xxx设置不同的过期时间
而对于写模式Spring Cache 并没有相应处理我们需要使用其它方式处理。 总的来说
1、对于常规数据读多写少及时性、一致性要求不高的数据完全可以使用 Spring Cache
2、对于特殊数据比如要求高一致性则需要特殊处理