1、SpringBoot整合Redis
1.1引入Redis依赖
<!-- Redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--Redis连接池的依赖--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
1.2配置Redis连接信息
spring:redis: # Redis配置host: 119.23.106.219port: 6379password: 123456lettuce: # springboot默认引入的是lettuce连接池,如果要是用jedis连接池需要引入jedis依赖pool:max-active: 8 # 最大连接max-idle: 8 # 最大空闲连接min-idle: 0 # 最小空闲连接max-wait: 1000ms # 连接等待时间
1.3编写Redis测试类
@SpringBootTestclass BlogApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid testString() {redisTemplate.opsForValue().set("ycl","杨存乐");Object name = redisTemplate.opsForValue().get("ycl");System.out.println(name);}}

但是用Redis连接工具查看,看到的是序列化的
点开源码看一下
if (this.defaultSerializer == null) {this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());}
1.4给RedisTemplate的key和values设置序列化
@Configurationpublic class RedisConfig {/*** 给RedisTemplate的key和values设置序列化* @param connectionFactory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){// 创建RedisTemplate对象RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置连接工厂template.setConnectionFactory(connectionFactory);// 创建JSON序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// 设置Key的序列化template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());// 设置Value的序列化template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);// 返回return template;}}
1.5测试序列化是否成功
1.6测试存入一个对象
/*** 测试存入一个对象*/@Testvoid testUser() {User user = new User();user.setUsername("杨存乐");user.setEmail("357487967@qq,com");redisTemplate.opsForValue().set("user:ycl",user);User user1 = (User) redisTemplate.opsForValue().get("user:ycl");System.out.println(user1.toString());}
1.7使用StringRedisTemplate操作数据
@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 测试存入一个对象用StringRedisTemplate操作*/@Testvoid testUser2() {User user = new User();user.setUsername("杨存乐");user.setEmail("357487967@qq,com");String userString = JSON.toJSONString(user);stringRedisTemplate.opsForValue().set("user:str:ycl", userString);String s = stringRedisTemplate.opsForValue().get("user:str:ycl");User user1 = JSON.parseObject(userString, User.class);System.out.println(user1);}
引入fastJSON依赖,用fastJSON手动序列化JSON
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.71</version></dependency>

2、缓存穿透
缓存穿透的原因:是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库,给数据库带来巨大的压力。
常见的两种解决方案:缓存空对象 布隆过滤
2.1缓存空对象
先查缓存,缓存没有查数据库,数据库再没有,缓存一个null对象(避免请求一直访问数据库),并设置一个过期时间(避免无用数据过多的占用Redis内存)
优点:实现简单,维护方便
缺点:额外的内存消耗可能造成短期的不一致
2.2布隆过滤

优点:内存占用较少,没有多余key
缺点:实现复杂存在误判可能
3、缓存雪崩
缓存雪崩的原因:在同一时间大量缓存的key失效或者Redis服务宕机,导致大量请求到达数据库,给数据库带来巨大的压力。
解决方案:
3.1给不同的key的过期时间设置随机值(避免在同一时间大量key过期)
3.2Redis做集群(防止Redis宕机)
3.3给缓存业务添加降级或限流策略
3.4给业务增加多级缓存
4、缓存击穿
缓存击穿的原因:一个被高频访问并且缓存重建业务比较复杂的key突然失效,无数的请求访问会在瞬间给数据库带来巨大的压力
常见的解决方案:互斥锁、逻辑过期
5、博客添加缓存

@Override@Transactionalpublic Blog queryBlog(Integer id) {// 先从Redis中查询Blog blog = redisUtil.getObject(RedisKeyConstants.Blog_INFO_KEY + id, Blog.class);if (ObjectUtil.isNotEmpty(blog)) {return blog;}// 从数据库查blog = getById(id);if (ObjectUtil.isNotEmpty(blog)) {// 写入RedisredisUtil.set(RedisKeyConstants.Blog_INFO_KEY + id, blog);}return blog;}
6、缓存更新策略

在项目中我们采用主动更新策略
主动更新又分为直接更新缓存和直接删除缓存
6.1直接更新缓存
好处就是下次查到的是最新的数据
缺点就是每次更新都有对缓存的操作,如果两次更新中没人访问,对缓存的无效写操作较多
6.2直接删除缓存
6.2.1先删除缓存,再更新数据库

由于操作缓存比更新数据库快,如果在更新的过程中,遇到查询缓存的线程,就会导致写入缓存的是更新前的数据,这样会导致数据库和缓存的数据不一致。
6.2.2先更新数据库,再删除缓存

由于写缓存比更新数据库要快得多,这种出现异常的情况非常少,所以采用这种。
@Override@Transactionalpublic Boolean updateBlog(Blog blog) {boolean b = updateById(blog);// 判断缓存key是否存在if (redisUtil.exists(RedisKeyConstants.Blog_INFO_KEY + blog.getId())) {// 若存在,删除缓存redisUtil.deleteKey(RedisKeyConstants.Blog_INFO_KEY + blog.getId());}return b;}
6.3延时双删

大概就是这么个意思,理解就行。



