学科分类
目录
Spring Boot开发

基于注解的Redis缓存实现

下面,在第一小节Spring Boot默认缓存管理的基础上引入Redis缓存组件,使用基于注解的方式讲解Spring Boot整合Redis缓存的具体实现。

(1)添加Spring Data Redis依赖启动器。在chapter06项目的pom.xml文件中添加Spring Data Redis依赖启动器,示例代码如下。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

(2)Redis服务连接配置。使用类似Redis第三方缓存组件进行缓存管理时,缓存数据并不是像Spring Boot默认缓存管理那样存储在内存中,而是需要预先搭建类似Redis服务的数据仓库进行缓存存储。所以,这里首先需要安装并开启Redis服务;然后在项目的全局配置文件application.properties中添加Redis服务的连接配置,示例代码如下。

# Redis服务地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=

(3)使用@Cacheable、@CachePut、@CacheEvict注解定制缓存管理。对CommentService类中的方法进行修改使用@Cacheable、@CachePut、@CacheEvict三个注解定制缓存管理,分别进行缓存存储、缓存更新和缓存删除的演示,修改后的内容如文件1所示。

文件1 CommentService.java

 1    import com.itheima.domain.Comment;
 2    import com.itheima.repository.CommentRepository;
 3    import org.springframework.beans.factory.annotation.Autowired;
 4    import org.springframework.cache.annotation.*;
 5    import org.springframework.stereotype.Service;
 6    import java.util.Optional;
 7    @Service
 8    public class CommentService {
 9        @Autowired
 10        private CommentRepository commentRepository;
 11        @Cacheable(cacheNames = "comment",unless = "#result==null")
 12        public Comment findById(int comment_id){
 13            Optional<Comment> optional = commentRepository.findById(comment_id);
 14            if(optional.isPresent()){
 15                return optional.get();
 16            }
 17            return null;
 18        }
 19        @CachePut(cacheNames = "comment",key = "#result.id")
 20        public Comment updateComment(Comment comment){
 21            commentRepository.updateComment(comment.getAuthor(), comment.getaId());
 22            return comment;
 23        }
 24        @CacheEvict(cacheNames = "comment")
 25        public void deleteComment(int comment_id){
 26            commentRepository.deleteById(comment_id);
 27        }
 28    }

文件1中,使用@Cacheable、@CachePut、@CacheEvict注解在数据查询、更新和删除方法上进行了缓存管理。其中,查询缓存@Cacheable注解中没有标记key值,将会使用默认参数值comment_id作为key进行数据保存,在进行缓存更新时必须使用同样的key;同时在查询缓存@Cacheable注解中,定义了“unless = "#result==null"”表示查询结果为空不进行缓存。

(4)基于注解的Redis查询缓存测试。通过前面的操作,已经在项目中添加了Redis缓存的依赖和Redis服务的连接配置,并且项目中已经使用@EnableCaching开启了基于注解的缓存管理,下面可以直接启动项目进行缓存测试。

启动chapter06项目,项目启动成功后,通过浏览器访问“http://localhost:8080/get/1”查询id为1的用户评论信息(务必确保连接的Redis服务已开启),会发现浏览器数据响应错误,同时控制台出现异常信息,效果如图1所示。

图1 Redis缓存管理异常信息

从图1可以看出,查询用户评论信息Comment时执行了相应的SQL语句,但是在进行缓存存储时出现了IllegalArgumentException非法参数异常,提示信息要求对应Comment实体类必须实现序列化(“DefaultSerializer requires a Serializable payload but received an object of type”)。

(5)将缓存对象实现序列化。通过前面的异常错误提示发现,在对实体类对象进行缓存存储时必须先实现序列化(一些基本数据类型不需要序列化,因为内部已经默认实现了序列化接口),否则会查询缓存异常,导致程序无法正常执行。下面,将进行缓存存储的Comment类进行改进,实现JDK自带的序列化接口Serializable,修改后的Comment类如文件2所示。

文件2 Comment.java

 1    import javax.persistence.*;
 2    import java.io.Serializable;
 3    @Entity(name = "t_comment")  // 设置ORM实体类,并指定映射的表名
 4    public class Comment implements Serializable {
 5        @Id   // 表明映射对应的主键id
 6        @GeneratedValue(strategy = GenerationType.IDENTITY) // 设置主键自增策略
 7        private Integer id;
 8        private String content;
 9        private String author;
 10        @Column(name = "a_id")  //指定映射的表字段名
 11        private Integer aId;
 12        // 省略属性getXX()和setXX()方法
 13        // 省略toString()方法
 14    }

(6)基于注解的Redis缓存查询测试。再次启动chapter06项目,项目启动成功后,通过浏览器继续访问“http://localhost:8080/get/1”查询id为1的用户评论信息,并重复刷新浏览器查询同一条数据信息,查询结果如图2所示。

图2 findById()方法查询结果

查看控制台打印的SQL查询语句,结果如图3所示。

图3 执行findById()方法控制台显示的SQL语句

从图2和3可以看出,执行findById()方法正确查询出用户评论信息Comment,在配置了Redis缓存组件后,重复进行同样的查询操作,数据库只执行了一次SQL语句。

还可以打开Redis客户端可视化管理工具Redis Desktop Manager连接本地启用的Redis服务,查看具体的数据缓存效果,效果如图4所示。

图4 Redis数据库可视化展示

从图4可以看出,执行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的用户评论信息,结果如图5所示。

图5 updateComment()方法更新后的查询结果

查看控制台打印的SQL查询语句,结果如图6所示。

图6 缓存更新后findById()方法控制台显示的SQL语句

从图5和6可以看出,执行updateComment()方法更新id为1的数据时执行了一条更新SQL语句,后续调用findById()方法查询id为1的用户评论信息时没有执行查询SQL语句,且浏览器正确返回了更新后的结果,表明@CachePut缓存更新配置成功。

(8)基于注解的Redis缓存删除测试。先通过浏览器访问“http://localhost:8080/delete/1”删除id为1的用户评论信息;接着,继续访问“http://localhost:8080/get/1”查询id为1的用户评论信息,结果如图7所示。

图7 deleteComment()方法删除后的查询结果

可以通过Redis客户端可视化管理工具Redis Desktop Manager查看对应数据删除后的缓存信息,如图8所示(需要选择Redis仓库名springbootredis并右键单击Reload进行刷新)。

图8 Redis数据库可视化展示

从图7和8可以看出,执行deleteComment()方法删除id为1的数据后查询结果为空,之前存储在Redis数据库的数据也被删除,表明@CacheEvict缓存删除成功实现。

通过上面的案例可以看出,使用基于注解的Redis缓存实现只需要添加Redis依赖并使用几个注解可以实现对数据的缓存管理。另外,还可以在Spring Boot全局配置文件中配置Redis有效期,示例代码如下:

# 对基于注解的Redis缓存数据统一设置有效期为1分钟,单位毫秒
spring.cache.redis.time-to-live=60000

上述代码中,在Spring Boot全局配置文件中添加了“spring.cache.redis.time-to-live”属性统一配置Redis数据的有效期(单位为毫秒),这种方式相对来说不够灵活,并且这种设置方式对下一节中将要讲解的基于API的Redis缓存实现没有效果。

点击此处
隐藏目录