赞
踩
1、缓存的读模式:
先读取缓存中的数据,如果有返回结果,如果没有查询数据库,放入缓存中,返回结果
2、缓存的写模式:
改了数据库的数据的时候,同时改了redis缓存中的数据
问题:A改了数据库数据,因为网络问题导致了没能及时写入缓存,而此时B改了数据库数据,立马把缓存中的数据改了,这时候A的修改的缓存数据为B的写入缓存数据之上
解决:为缓存数据设置过期时间,但会出现暂时性的脏数据问题,实现最终一致性
改了数据库的数据的时候,把redis缓存中的数据删了,等待下次主动查询进行更新
问题:A改了数据库,执行完了,删除缓存,B也改数据库,花的时间比较长,此时C网络快,查缓存发现没数据,读取了A修改的数据库老数据,然后C要更新缓存,此时因为网络问题更新慢,此时B写完了数据库立马把缓存删了,C此时把读取A的老数据写到了缓存中,最新的数据B没能放入缓存中
解决:加锁解决(笨重)
解决方案:
无论双写还是失效都会导致缓存不一致问题
1、如果是用户纬度数据(订单数据、用户数据),这种并发几率非常小,不用考虑这个问题,缓存数据加 上过期时间,每隔一段时间触发读的主动更新即可
2、如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式。
3、缓存数据+过期时间也足够解决大部分业务对于缓存的要求。
4、通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。(业务不关心 脏数据,允许临时脏数据可忽略);
总结:
1、整合springCache简化缓存开发
1)、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2)、写配置
(1)、自动配置了哪些
自动配好了缓存过滤器RedisCacheConfiguration
自动配好了缓存过滤器RedisCacheManager
(2)、配置redis作为缓存
(3)、测试使用缓存
1)、开启缓存功能@Enablecaching
2)、只需要使用注解就能完成缓存操作
在application.priperties配置cache
#配置缓存类型使用redis
spring.cache.type=redis
#指定缓存的名字以后缓存名字全部按配置的来,不配置的话系统中用到哪些缓存自动创建出来
spring.cache.cache-name=qq
#设置存活时间,毫秒为单位
spring.cache.redis.time-to-live=3600000
#如果指定了前缀就用我们指定的前缀,如果没有就没人使用缓存的名字作为前缀
spring.cache.redis.key-prefix=CACHE_
spring.cache.redis.use-key-prefix=false
#是否缓存空值。防止缓存穿透
spring.cache.redis.cache-null-values=true
测试使用缓存
@Cacheable:触发将数据保存到缓存的操作
@CacheEvict:触发将数据从缓存删除的操作
@CahePut:不影响方法执行更新缓存
@Caching:组合以上多个操作
@CacheConfig:在类级别共享缓存的相同配置
开启缓存
1)、开启缓存功能
开启缓存功能使用**@Enablecaching**,在启动类上加上开启
只需要使用注解就能完成缓存操作
如:
配置Config
import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @EnableConfigurationProperties(CacheProperties.class) @Configuration @EnableCaching //开启缓存 public class MyCacheConfig { // @Autowired // CacheProperties cacheProperties; /** * 配置文件中的东西没有用上: * 1、原来和配置文件绑定的配置类是这样子的 * * 2、要让他生效 * * @return */ @Bean RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();//默认配置 // config =config.entryTtl(); 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; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。