5.2 整合 Redis 缓存实现
5.2.1 Spring Boot 支持的缓存组件
在 Spring Boot 中,数据的缓存管理存储依赖于 Spring 框架中 cache 相关的 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 缓存管理器接口。
如果程序中没有定义类型为 CacheManager 的 Bean 组件或者是名为 cacheResolver 的 CacheResolver 缓存解析器,Spring Boot 将尝试选择并启用以下缓存组件(按照指定的顺序):
(1)Generic
(2)JCache (JSR-107) (EhCache 3、Hazelcast、Infinispan 等)
(3)EhCache 2.x
(4)Hazelcast
(5)Infinispan
(6)Couchbase
(7)Redis
(8)Caffeine
(9)Simple
上面按照 Spring Boot 缓存组件的加载顺序,列举了支持的 9 种缓存组件,在项目中添加某个缓存管理组件(例如 Redis)后,Spring Boot 项目会选择并启用对应的缓存管理器。如果项目中同时添加了多个缓存组件,且没有指定缓存管理器或者缓存解析器(CacheManager 或者 cacheResolver),那么 Spring Boot 会按照上述顺序在添加的多个缓存中优先启用指定的缓存组件进行缓存管理。
刚刚讲解的 Spring Boot 默认缓存管理中,没有添加任何缓存管理组件能实现缓存管理。这是因为开启缓存管理后,Spring Boot 会按照上述列表顺序查找有效的缓存组件进行缓存管理,如果没有任何缓存组件,会默认使用最后一个 Simple 缓存组件进行管理。Simple 缓存组件是 Spring Boot 默认的缓存管理组件,它默认使用内存中的 ConcurrentMap 进行缓存存储,所以在没有添加任何第三方缓存组件的情况下,可以实现内存中的缓存管理,但是我们不推荐使用这种缓存管理方式
5.2.2 基于注解的 Redis 缓存实现
在 Spring Boot 默认缓存管理的基础上引入 Redis 缓存组件,使用基于注解的方式讲解 Spring Boot 整合 Redis 缓存的具体实现
(1)添加 Spring Data Redis 依赖启动器。在 pom.xml 文件中添加 Spring Data Redis 依赖启动器
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
当我们添加进 redis 相关的启动器之后, SpringBoot 会使用 `RedisCacheConfigratioin` 当做生效的自动配置类进行缓存相关的自动装配, 容器中使用的缓存管理器是
`RedisCacheManager`, 这个缓存管理器创建的 Cache 为 `RedisCache`, 进而操控 redis 进行数据的缓存
(2)Redis 服务连接配置
“`properties
# Redis 服务地址
spring.redis.host=127.0.0.1
# Redis 服务器连接端口
spring.redis.port=6379
# Redis 服务器连接密码(默认为空)
spring.redis.password=
“`
(3)对 CommentService 类中的方法进行修改使用 @Cacheable、@CachePut、@CacheEvict 三个注解定制缓存管理,分别进行缓存存储、缓存更新和缓存删除的演示
“`java
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
@Cacheable(cacheNames = “comment”,unless = “#result==null”)
public Comment findCommentById(Integer id){
Optional<Comment> comment = commentRepository.findById(id);
if(comment.isPresent()){
Comment comment1 = comment.get();
return comment1;
}
return null;
}
@CachePut(cacheNames = “comment”,key = “#result.id”)
public Comment updateComment(Comment comment) {
commentRepository.updateComment(comment.getAuthor(), comment.getaId());
return comment;
}
@CacheEvict(cacheNames = “comment”)
public void deleteComment(int comment_id) {
commentRepository.deleteById(comment_id);
}
}
“`
以上 使用 @Cacheable、@CachePut、@CacheEvict 注解在数据查询、更新和删除方法上进行了缓存管理。
其中,查询缓存 @Cacheable 注解中没有标记 key 值,将会使用默认参数值 comment_id 作为 key 进行数据保存,在进行缓存更新时必须使用同样的 key;同时在查询缓存 @Cacheable 注解中,定义了“unless = “#result==null””表示查询结果为空不进行缓存
(4)基于注解的 Redis 查询缓存测试
![image-20191231141712756](./images/image-20191231141712756.png)
可以看出,查询用户评论信息 Comment 时执行了相应的 SQL 语句,但是在进行缓存存储时出现了 IllegalArgumentException 非法参数异常,提示信息要求对应 Comment 实体类必须实现序列化(“DefaultSerializer requires a Serializable payload but received an object of type”)。
(5)将缓存对象实现序列化。
<img src=”./images/image-20191231141845520.png” alt=”image-20191231141845520″ style=”zoom:67%;” />
(6)再次启动测试
访问“http://localhost:8080/findCommentById?id=1”查询 id 为 1 的用户评论信息,并重复刷新浏览器查询同一条数据信息,查询结果
![image-20191231142056554](./images/image-20191231142056554.png)
查看控制台打印的 SQL 查询语句
![image-20191231142114105](./images/image-20191231142114105.png)
还可以打开 Redis 客户端可视化管理工具 Redis Desktop Manager 连接本地启用的 Redis 服务,查看具体的数据缓存效果
![image-20191231142353290](./images/image-20191231142353290.png)
执行 findById() 方法查询出的用户评论信息 Comment 正确存储到了 Redis 缓存库中名为 comment 的名称空间下。其中缓存数据的唯一标识 key 值是以“名称空间 comment::+ 参数值(comment::1)”的字符串形式体现的,而 value 值则是经过 JDK 默认序列格式化后的 HEX 格式存储。这种 JDK 默认序列格式化后的数据显然不方便缓存数据的可视化查看和管理,所以在实际开发中,通常会自定义数据的序列化格式
(7)基于注解的 Redis 缓存更新测试。
先通过浏览器访问“http://localhost:8080/update/1/shitou”更新 id 为 1 的评论作者名为 shitou;
接着,继续访问“http://localhost:8080/get/1”查询 id 为 1 的用户评论信息
<img src=”./images/image-20191231144329586.png” alt=”image-20191231144329586″ style=”zoom:67%;” />
![image-20191231144533512](./images/image-20191231144533512.png)
可以看出,执行 updateComment() 方法更新 id 为 1 的数据时执行了一条更新 SQL 语句,后续调用 findById() 方法查询 id 为 1 的用户评论信息时没有执行查询 SQL 语句,且浏览器正确返回了更新后的结果,表明 @CachePut 缓存更新配置成功
(8)基于注解的 Redis 缓存删除测试
通过浏览器访问“http://localhost:8080/deleteComment?id=1”删除 id 为 1 的用户评论信息;
![image-20191231145925740](./images/image-20191231145925740.png)
执行 deleteComment() 方法删除 id 为 1 的数据后查询结果为空,之前存储在 Redis 数据库的 comment 相关数据也被删除,表明 @CacheEvict 缓存删除成功实现
通过上面的案例可以看出,使用基于注解的 Redis 缓存实现只需要添加 Redis 依赖并使用几个注解可以实现对数据的缓存管理。另外,还可以在 Spring Boot 全局配置文件中配置 Redis 有效期,示例代码如下:
“`properties
# 对基于注解的 Redis 缓存数据统一设置有效期为 1 分钟,单位毫秒
spring.cache.redis.time-to-live=60000
“`
上述代码中,在 Spring Boot 全局配置文件中添加了“spring.cache.redis.time-to-live”属性统一配置 Redis 数据的有效期(单位为毫秒),但这种方式相对来说不够灵活
刚学了拉勾教育的《Java 工程师高薪训练营》,看到刚学到的点就回答了。希望拉勾能给我推到想去的公司,目标:字节!!