这篇文章主要讲解了“SpringBoot用redis实现数据缓存”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot用Redis实现数据缓存”吧!
创新互联公司长期为上千多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为德城企业提供专业的做网站、网站建设,德城网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。
一、缓存概念知识
1、是什么缓存
我们日常生活中,经常会接触听到缓存这个词,例如,浏览器清空缓存,处理器缓存大小,磁盘缓存等等。经过分类,可以将缓存分为:
硬件缓存:一般指的是机器上的 CPU、硬盘等等组件的缓存区间,一般是利用的内存作为一块中转区域,都通过内存交互信息,减少系统负载,提供传输效率。
客户端缓存:一般指的是某些应用,例如浏览器、手机App、视频缓冲等等,都是在加载一次数据后将数据临时存储到本地,当再次访问时候先检查本地缓存中是否存在,存在就不必去远程重新拉取,而是直接读取缓存数据,这样来减少远端服务器压力和加快载入速度。
服务端缓存:一般指远端服务器上,考虑到客户端请求量多,某些数据请求量大,这些热点数据经常要到数据库中读取数据,给数据库造成压力,还有就是 IO、网络等原因有一定延迟,响应客户端较慢。所以,在一些不考虑实时性的数据中,经常将这些数据存在内存中(内存速度非常快),当请求时候,能够直接读取内存中的数据及时响应,借鉴Redis实战学习笔记。
2、为什么使用缓存
用缓存,主要有解决 高性能 与 高并发 与 减少数据库压力。缓存本质就是将数据存储在内存中,当数据没有发生本质变化的时候,我们应尽量避免直接连接数据库进行查询,因为并发高时很可能会将数据库压塌,而是应去缓存中读取数据,只有缓存中未查找到时再去数据库中查询,这样就大大降低了数据库的读写次数,增加系统的性能和能提供的并发量。

3、缓存的优缺点
优点:
加快了响应速度
减少了对数据库的读操作,数据库的压力降低。
缺点:
二、Redis 概念知识
1、什么是 Redis
Redis 是一个高性能的 Key-Value 数据库,它是完全开源免费的,而且 Redis 是一个 NOSQL 类型数据库,是为了解决 高并发、高扩展,大数据存储 等一系列的问题而产生的数据库解决方案,是一个非关系型的数据库。但是,它也是不能替代关系型数据库,只能作为特定环境下的扩充。
2、为什么使用 Redis 作为缓存
支持高可用:Redis 支持 master\slave 主\从机制、sentinal 哨兵模式、cluster 集群模式,这样大大保证了 Redis 运行的稳定和高可用行。
支持多种数据结构:Redis 不仅仅支持简单的 Key/Value 类型的数据,同时还提供 list、set、zset、hash 等数据结构的存储。
支持数据持久化:可以将内存中的数据持久化在磁盘中,当宕机或者故障重启时,可以再次加载进如 Redis,从而不会或减少数据的丢失。
有很多工具与插件对其支持:Redis 已经在业界广泛使用,已经是成为缓存的首选目标,所以很多语言和工具对其支持,我们只需要简单的操作就可以轻松使用。

3、Redis 支持的数据类型
Redis 支持的数据结构类型包括:
字符串(string)
哈希表(hash)
列表(list)
集合(set)
有序集合(zset)
为了保证读取的效率,Redis 把数据对象都存储在内存当中,它可以支持周期性的把更新的数据写入磁盘文件中。而且它还提供了交集和并集,以及一些不同方式排序的操作。
三、缓存后可能遇见的问题
1、缓存穿透

缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
缓存穿透几种解决办法:
缓存空值,在从 DB 查询对象为空时,也要将空值存入缓存,具体的值需要使用特殊的标识, 能和真正缓存的数据区分开,另外将其过期时间设为较短时间。
使用布隆过滤器,布隆过滤器能判断一个 key 一定不存在(不保证一定存在,因为布隆过滤器结构原因,不能删除,但是旧值可能被新值替换,而将旧值删除后它可能依旧判断其可能存在),在缓存的基础上,构建布隆过滤器数据结构,在布隆过滤器中存储对应的 key,如果存在,则说明 key 对应的值为空。
2、缓存击穿

缓存击穿:某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。
缓存击穿几种解决办法:
3、缓存雪崩

缓存雪崩:当缓存服务器重启、或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力,造成数据库后端故障,从而引起应用服务器雪崩。
缓存雪崩几种解决办法:
缓存组件设计高可用,缓存高可用是指,存储缓存的组件的高可用,能够防止单点故障、机器故障、机房宕机等一系列问题。例如 Redis sentinel 和 Redis Cluster,都实现了高可用。
请求限流与服务熔断降级机制,限制服务请求次数,当服务不可用时快速熔断降级。
设置缓存过期时间一定的随机分布,避免集中在同一时间缓存失效。
定时更新缓存策略,对于实时性要求不高的数据,定时进行更新。
4、缓存一致性
使用缓存很大可能导致数据不一致问题,如下:
更熟数据库成功 -> 更新缓存失败 -> 数据不一致
更新缓存成功 -> 更新数据库失败 -> 数据不一致
更新数据库成功 -> 淘汰缓存失败 -> 数据不一致
淘汰缓存成功 -> 更新数据库失败 -> 查询缓存mis
所以使用缓存时候,应该结合实际情况,考虑缓存的数据是否有一致性需求。
四、SpringBoot 如何结合 Redis 实现缓存
1、Mavne 引入相关依赖

2、配置 Redis 参数
application 文件中添加连接 Redis 的配置参数
Redis 单机配置:

Redis 哨兵配置:

Redis 集群配置:

3、配置 Spring 缓存管理器
@Configuration
public class RedisConfig {
/**
* 配置缓存管理器
* @param factory Redis 线程安全连接工厂
* @return 缓存管理器
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
// 生成两套默认配置,通过 Config 对象即可对缓存进行自定义配置
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
// 设置过期时间 10 分钟
.entryTtl(Duration.ofMinutes(10))
// 设置缓存前缀
.prefixKeysWith("cache:user:")
// 禁止缓存 null 值
.disableCachingNullValues()
// 设置 key 序列化
.serializeKeysWith(keyPair())
// 设置 value 序列化
.serializeValuesWith(valuePair());
// 返回 Redis 缓存管理器
return RedisCacheManager.builder(factory)
.withCacheConfiguration("user", cacheConfig).build();
}
/**
* 配置键序列化
* @return StringRedisSerializer
*/
private RedisSerializationContext.SerializationPair keyPair() {
return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());
}
/**
* 配置值序列化,使用 GenericJackson2JsonRedisSerializer 替换默认序列化
* @return GenericJackson2JsonRedisSerializer
*/
private RedisSerializationContext.SerializationPair