Spring Boot 整合 Redis
第一步,在 pom.xml 文件中添加 Redis 的 starter。
1 | <dependency> |
第二步,在 application.yml 文件中添加 Redis 的配置信息
1 | spring: |
第三步,在测试类中添加以下代码。
1 |
|
RedisTemplate 和 StringRedisTemplate 都是 Spring Data Redis 提供的模板类,可以对 Redis 进行操作,后者针对键值对都是 String 类型的数据,前者可以是任何类型的对象。
RedisTemplate 和 StringRedisTemplate 除了提供 opsForValue 方法来操作字符串之外,还提供了以下方法:
- opsForList:操作 list
- opsForSet:操作 set
- opsForZSet:操作有序 set
- opsForHash:操作 hash
运行测试类后可以在控制台看到以下输出信息:
也可以通过 AnotherRedisDesktopManager 客户端查看 Redis 数据库中的数据。
编程喵整合 Redis
编程喵是一个 Spring Boot + Vue 的前后端分离项目,要整合 Redis 的话,最好的方式是使用 Spring Cache,仅仅通过 @Cacheable、@CachePut、@CacheEvict、@EnableCaching 等注解就可以轻松使用 Redis 做缓存了。
1)@EnableCaching,开启缓存功能。
2)@Cacheable,调用方法前,去缓存中找,找到就返回,找不到就执行方法,并将返回值放到缓存中。
3)@CachePut,方法调用前不会去缓存中找,无论如何都会执行方法,执行完将返回值放到缓存中。
4)@CacheEvict,清理缓存中的一个或多个记录。
Spring Cache 是 Spring 提供的一套完整的缓存解决方案,虽然它本身没有提供缓存的实现,但它提供的一整套接口、规范、配置、注解等,可以让我们无缝衔接 Redis、Ehcache 等缓存实现。
Spring Cache 的注解(前面提到的四个)会在调用方法之后,去缓存方法返回的最终结果;或者在方法调用之前拿缓存中的结果,当然还有删除缓存中的结果。
这些读写操作不用我们手动再去写代码实现了,直接交给 Spring Cache 来打理就 OK 了,是不是非常贴心?
第一步,在 pom.xml 文件中追加 Redis 的 starter。
1 | <dependency> |
第二步,在 application.yml 文件中添加 Redis 链接配置。
1 | spring: |
第三步,新增 RedisConfig.java 类,通过 RedisTemplate 设置 JSON 格式的序列化器,这样的话存储到 Redis 里的数据将是有类型的 JSON 数据,例如:
1 |
|
通过 RedisCacheConfiguration 设置超时时间,来避免产生很多不必要的缓存数据。
1 |
|
第四步,在标签更新接口中添加 @CachePut 注解,也就是说方法执行前不会去缓存中找,但方法执行完会将返回值放入缓存中。
1 |
|
注意看 @CachePut 注解这行代码:
1 |
- value:缓存名称,也就是缓存的命名空间,value 这里应该换成 namespace 更好一点;
- key:用于在命名空间中缓存的 key 值,可以使用 SpEL 表达式,比如说
'codingmore:postags:'+#postAddTagParam.postTagId
; - 还有两个属性 unless 和 condition 暂时没用到,分别表示条件符合则不缓存,条件符合则缓存。
第五步,启动服务器端,启动客户端,修改标签进行测试。
通过 Red 客户端(一款 macOS 版的 Redis 桌面工具),可以看到刚刚更新的返回值已经添加到 Redis 中了。
使用 Redis 连接池
Redis 是基于内存的数据库,本来是为了提高程序性能的,但如果不使用 Redis 连接池的话,建立连接、断开连接就需要消耗大量的时间。
用了连接池,就可以实现在客户端建立多个连接,需要的时候从连接池拿,用完了再放回去,这样就节省了连接建立、断开的时间。
要使用连接池,我们得先了解 Redis 的客户端,常用的有两种:Jedis 和 Lettuce。
- Jedis:Spring Boot 1.5.x 版本时默认的 Redis 客户端,实现上是直接连接 Redis Server,如果在多线程环境下是非线程安全的,这时候要使用连接池为每个 jedis 实例增加物理连接;
- Lettuce:Spring Boot 2.x 版本后默认的 Redis 客户端,基于 Netty 实现,连接实例可以在多个线程间并发访问,一个连接实例不够的情况下也可以按需要增加连接实例。
它俩在 GitHub 上都挺受欢迎的,大家可以按需选用。
我这里把两种客户端的情况都演示一下,方便小伙伴们参考。
1)Lettuce
第一步,修改 application-dev.yml,添加 Lettuce 连接池配置(pool 节点)。
1 | spring: |
第二步,在 pom.xml 文件中添加 commons-pool2 依赖,否则会在启动的时候报 ClassNotFoundException 的错。这是因为 Spring Boot 2.x 里默认没启用连接池。
1 | Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig |
添加 commons-pool2 依赖:
1 | <dependency> |
重新启动服务,在 RedisConfig 类的 redisTemplate 方法里对 redisTemplate 打上断点,debug 模式下可以看到连接池的配置信息(redisConnectionFactory→clientConfiguration→poolConfig
)。如下图所示。
如果在 application-dev.yml 文件中没有添加 Lettuce 连接池配置的话,是不会看到
2)Jedis
第一步,在 pom.xml 文件中添加 Jedis 依赖,去除 Lettuce 默认依赖。
1 | <dependency> |
第二步,修改 application-dev.yml,添加 Jedis 连接池配置。
1 | spring: |
启动服务后,观察 redisTemplate 的 clientConfiguration 节点,可以看到它的值已经变成 DefaultJedisClientConfiguration 对象了。
当然了,也可以不配置 Jedis 客户端的连接池,走默认的连接池配置。因为 Jedis 客户端默认增加了连接池的依赖包,在 pom.xml 文件中点开 Jedis 客户端依赖可以查看到。
自由操作 Redis
Spring Cache 虽然提供了操作 Redis 的便捷方法,比如我们前面演示的 @CachePut 注解,但注解提供的操作非常有限,比如说它只能保存返回值到缓存中,而返回值并不一定是我们想要保存的结果。
与其保存这个返回给客户端的 JSON 信息,我们更想保存的是更新后的标签。那该怎么自由地操作 Redis 呢?
第一步,增加 RedisService 接口:
1 | public interface RedisService { |
第二步,增加 RedisServiceImpl 实现类:
1 |
|
第三步,在标签 PostTagController 中增加 Redis 测试用接口 simpleTest :
1 |
|
第四步 ,重启服务,使用 Knife4j 测试该接口 :
然后通过 Red 查看该缓存,OK,确认我们的代码是可以完美执行的。
项目源码
编程喵:https://github.com/itwanger/coding-more
整合 Redis 专用:https://github.com/itwanger/coding-more