点击上方☝SpringForAll社区 轻松关注!及时获取有趣有料的技术文章

本文来源:http://www.mydlq.club/article/55/

. 一、缓存概念知识

. 1、是什么缓存

. 2、为什么使用缓存

. 3、缓存的优缺点

. 二、Redis 概念知识

. 1、什么是 Redis

. 2、为什么使用 Redis 作为缓存

. 3、Redis 支持的数据类型

. 三、缓存后可能遇见的问题

. 1、缓存穿透

. 2、缓存击穿

. 3、缓存雪崩

. 4、缓存一致性

. 四、SpringBoot 如何结合 Redis 实现缓存

. 1、Mavne 引入相关依赖

. 2、配置 Redis 参数

. 3、配置 Spring 缓存管理器

. 4、服务中使用 SpringCache 的注解

. 5、启动类添加开启缓存注解


系统环境:

  • Redis 版本:5.0.7

  • SpringBoot 版本:2.2.2.RELEASE

参考地址:

  • Redus 官方网址:https://redis.io/

  • 博文示例项目 Github 地址:https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-redis-cache-example

一、缓存概念知识

1、是什么缓存

我们日常生活中,经常会接触听到缓存这个词,例如,浏览器清空缓存,处理器缓存大小,磁盘缓存等等。经过分类,可以将缓存分为:

  • 硬件缓存: 一般指的是机器上的 CPU、硬盘等等组件的缓存区间,一般是利用的内存作为一块中转区域,都通过内存交互信息,减少系统负载,提供传输效率。

  • 客户端缓存: 一般指的是某些应用,例如浏览器、手机App、视频缓冲等等,都是在加载一次数据后将数据临时存储到本地,当再次访问时候先检查本地缓存中是否存在,存在就不必去远程重新拉取,而是直接读取缓存数据,这样来减少远端服务器压力和加快载入速度。

  • 服务端缓存: 一般指远端服务器上,考虑到客户端请求量多,某些数据请求量大,这些热点数据经常要到数据库中读取数据,给数据库造成压力,还有就是 IO、网络等原因有一定延迟,响应客户端较慢。所以,在一些不考虑实时性的数据中,经常将这些数据存在内存中(内存速度非常快),当请求时候,能够直接读取内存中的数据及时响应。

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 引入相关依赖

  • spring-boot-starter-data-redis

  • commons-pool2

org.springframework.boot

spring-boot-starter-data-redis

org.springframework.boot

spring-boot-starter-cache

org.apache.commons

commons-pool2

2、配置 Redis 参数

application 文件中添加连接 Redis 的配置参数

  • Redis 单机配置:

spring:

redis:

host: 127.0.0.1 #Redis 地址

port: 6379 #Redis 端口号

database: 0 #Redis 索引(0~15,默认为0)

timeout: 1000 #Redis 连接的超时时间

password: 123456 #Redis 密码,如果没有就默认不配置此参数

lettuce: #使用 lettuce 连接池

pool:

max-active: 20 #连接池最大连接数(使用负值表示没有限制)

max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)

min-idle: 0 #连接池中的最大空闲连接

max-idle: 10 #连接池中的最小空闲连接

  • Redis 哨兵配置:

spring:

redis:

sentinel: #哨兵配置

master: "my-master"

nodes: "192.168.2.11:6379,192.168.2.12:6379,192.168.2.13:6379"

database: 0 #Redis 索引(0~15,默认为0)

timeout: 1000 #Redis 连接的超时时间

password: 123456 #Redis 密码,如果没有就默认不配置此参数

lettuce: #使用 lettuce 连接池

pool:

max-active: 20 #连接池最大连接数(使用负值表示没有限制)

max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)

min-idle: 0 #连接池中的最大空闲连接

max-idle: 10 #连接池中的最小空闲连接

  • Redis 集群配置:

spring:

redis:

cluster: #redis 集群配置

max-redirects: 5 #redis命令执行时最多转发次数

nodes: "192.168.2.11:6379,192.168.2.12:6379,192.168.2.13:6379"

database: 0 #Redis 索引(0~15,默认为0)

timeout: 1000 #Redis 连接的超时时间

password: 123456 #Redis 密码,如果没有就默认不配置此参数

lettuce: #使用 lettuce 连接池

pool:

max-active: 20 #连接池最大连接数(使用负值表示没有限制)

max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)

min-idle: 0 #连接池中的最大空闲连接

max-idle: 10 #连接池中的最小空闲连接

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<String> keyPair() {

return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());

}

/**

* 配置值序列化,使用 GenericJackson2JsonRedisSerializer 替换默认序列化

* @return GenericJackson2JsonRedisSerializer

*/

private RedisSerializationContext.SerializationPair<Object> valuePair() {

return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());

}

}

4、服务中使用 SpringCache 的注解

@Service

@CacheConfig(cacheNames = "user")

public class UserServiceImpl implements UserService {

/**

* 新增用户

*/

public User addUser(User user) {

......

}

/**

* 查询用户

*/

@Cacheable(key = "#username")

public User getUserByUsername(String username) {

......

}

/**

* 更新用户

*/

@CachePut(key = "#user.username")

public User updateUser(User user) {

......

}

/**

* 删除用户

*/

@CacheEvict(key = "#username")

public void deleteByUsername(String username) {

......

}

}

注解说明:

  • @CacheConfig: 一般配置在类上,指定缓存名称,这个名称是和上面“置缓存管理器”中缓存名称的一致。

  • @Cacheable: 作用于方法上,用于对于方法返回结果进行缓存,如果已经存在该缓存,则直接从缓存中获取,缓存的key可以从入参中指定,缓存的 value 为方法返回值。

  • @CachePut: 作用于方法上,无论是否存在该缓存,每次都会重新添加缓存,缓存的key可以从入参中指定,缓存的value为方法返回值,常用作于更新。

  • @CacheEvict: 作用于方法上,用于清除缓存

  • @Caching: 作用于方法上,用于一次性设置多个缓存。

上面注解中的常用配置参数:

  • value: 缓存管理器中配置的缓存的名称,这里可以理解为一个组的概念,缓存管理器中可以有多套缓存配置,每套都有一个名称,类似于组名,这个可以配置这个值,选择使用哪个缓存的名称,配置后就会应用那个缓存名称对应的配置。

  • key: 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。

  • condition: 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。

  • unless: 不缓存的条件,和 condition 一样,也是 SpEL 编写,返回 true 或者 false,为 true 时则不进行缓存。

5、启动类添加开启缓存注解

@EnableCaching

@SpringBootApplication

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

  • @EnableCaching: 作用于类上,用于开启注解功能。

● 手把手教你将 Java 项目推送到 Maven 中央仓库实践

● Java 通过 JavaMail 发送邮件原来这么简单?

● SpringBoot 中优雅处理参数验证,到底发生了什么?

● Java人应该知道的SpringBoot For Kafka (上)

● Java人应该知道的SpringBoot For Kafka (下)

● SpringBoot 多种读取配置文件中参数的方式

● SpringBoot 操作 ElasticSearch 详解

● SpringBoot 使用 Caffeine 本地缓存

● Github推出了GitHub CLI

● (很全面)SpringBoot 集成 Apollo 配置中心

● 你知道如何成为一名靠谱的架构师不?

● Tomcat 在 SpringBoot 中是如何启动的?

● SpringBoot 深度调优,让你的项目飞起来!

● 8种经常被忽视的SQL错误用法,你有没有踩过坑?

● Java面试应该知道之深入理解Java的接口和抽象类

redis lettuce 超时_Spring Cache 操作 Redis 实现数据缓存(上)相关推荐

  1. SpringBoot 结合 Spring Cache 操作 Redis 实现数据缓存

    点击上方"后端技术精选",选择"置顶公众号" 技术文章第一时间送达! 作者:超级小豆丁 http://www.mydlq.club/article/55/ 系统 ...

  2. c# redis 如何设置过期时间_Spring cache整合Redis,并给它一个过期时间!

    小Hub领读: 不知道你们有没给cache设置过过期时间,来试试? 上一篇文章中,我们使用springboot集成了redis,并使用RedisTemplate来操作缓存数据,可以灵活使用. 我才懂! ...

  3. java dataset redis,利用Spring-Data-Redis和Jedis操作Redis缓存

    概述          Jedis是redis官方推荐的用于访问Java客户端,在https://github.com/xetorthio/jedis下载最新的jedis. 访问redis 1.访问简 ...

  4. go操作redis之go-redis,python操作redis之redis

    目录 go操作redis go-redis安装 连接方式 单机连接 TLS连接模式 Redis 集群连接 Redis 哨兵模式连接 基本使用 执行任意命令 redis.Nil zset操作 扫描或遍历 ...

  5. 【Redis】7.使用jedis操作redis数据库

    jedis jedis是java程序操纵Redis的工具. Jedis是Redis官方推荐的Java链接工具 使用前导入,下面的测试建议也导入测试的包 <!-- 导入jedis的包--> ...

  6. Redis概述_使用命令对redis的数据进行增删改查_Jedis连接redis进行数据操作_redis进行数据缓存案例

    学习目标 redis 概念 下载安装 命令操作 1. 数据结构 持久化操作 使用Java客户端操作redis Redis 前言(从百度上抄的, 看看了解一下, 懒得排版了) 1. 概念: redis是 ...

  7. redis实例python_使用python操作redis(管道)

    一.redis连接 redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRe ...

  8. docker安装redis,使用jedis轻松操作redis

    之前,已经在虚拟机的linux环境中安装好了docker,再安装redis就会变得非常简单. docker search redis 查询docker容器支持的redis版本 默认安装latest最新 ...

  9. redis和mysql的衔接操作(redis加速mysql)

    redis和mysql的衔接 1. 配置架构 1.1 配置mysql和redis连接 1.2 配置mysql数据库 1.3 安装redis数据库 1.4 测试 2. redis和mysql的实时同步 ...

最新文章

  1. 冒号课堂§2.4:并发范式
  2. C4D中重点、难点分析
  3. 可视化_仓库管理可视化
  4. flowable支持的mysql版本_Flowable3-配置
  5. 新疆大学OJ(ACM) 1099: 数列有序!
  6. python的sorted函数对字典按key排序和按value排序
  7. hbuilder - wap to app
  8. mc服务器隐藏指令显示,服务器常用指令 搬运自Mc服主网
  9. 敏捷开发产品管理系列之三:产品用户群规划
  10. 再说变体结构 - 回复 彬 的问题
  11. 0819 - 要想富,追新不守旧
  12. ctc decoder
  13. UnicodeTOGB,能够将Unicode串转换成GB码
  14. 【总结】程序员运营公众号一年总结
  15. python精灵和精灵组_Pygame精灵和精灵组
  16. 第四届“橙瓜网络文学奖”暨见证·网络文学20年评选各类型十佳大神入围名单
  17. html/css笔记 文本添加下划线方法
  18. gnome菜单图标显示
  19. DIY 一个树莓派无人机
  20. 惠普笔记本电脑驱动程序下载地址一览表

热门文章

  1. jmeter配置元件之计数器
  2. TypeScript完全解读(26课时)_2.TypeScript完全解读-基础类型
  3. plus.webview.create( url, id, styles, extras )参数及说明
  4. Yaml spring boot 二维数组写法
  5. 关于php变量的赋值和引用的区别
  6. web前端性能调优(转载)
  7. 给员工授予svn相关权限
  8. 一个程序员一月的开销统计分析、(附上PC端和移动端android源码)
  9. 博客转移到cnblogs
  10. 云服务器上安装Anaconda3 (亲测有效)