初学Springboot(七)


前言

本次我们来一起学习Springboot的缓存,主要是默认缓存的体验以及Redis的使用


提示:以下是本篇文章正文内容,下面案例可供参考

一、Springboot缓存管理的作用

缓存是分布式系统中的重要组件,主要解决数据库数据的高并发访问。在实际开发中,尤其是用户访问量较大的网站,用户对高频热点数据的访问非常频繁,为了提高服务器访问性能、减少数据库的压力、提高用户体验,使用缓存显得尤为重要。

二、基础环境的搭建

1.创建环境

在这里插入图片描述

在这里插入图片描述
分别引入JPA,Web,MySQL以及待会会用到的Redis()先别导入,先试用一下默认的缓存组件 依赖启动器。

2.数据库创建两张表(t_article和t_comment),并创建对应的实体类

在数据库中创建对应的库(这里我用的是之前的库Springboottest1),并生成两张表。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.在IDEA中创建实体类domain

//该实体类与哪张表互相映射
@Entity(name = "t_comment")
public class Comment {
    @Id//表示映射对应的主键
    //表示主键生成策略(自动增长)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String content;
    private String author;
    //指定映射的表字段名(表中的名字就是注解的name)
    @Column(name = "a_id")
    private Integer aId;
    (getset方法略)

4.创建实体类的接口

repository(接口)对JPA语句进行拓展修改(导包别导错)

import com.gdcp.domain.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import javax.transaction.Transactional;

public interface CommentRepository extends JpaRepository<Comment,Integer> {
    //根据评论id修改评论作者评论作者author
    @Transactional//进行数控
    @Modifying//对数据库进行变更必须加
    @Query("UPDATE t_comment c SET c.author=?1 where  c.id=?2")
    public int updateComment(String author,Integer id);
}

5.service(业务操作类)在该类中编写数据的查询、修改和删除操作

@Service
public class CommentService {
    @Autowired
    private CommentRepository commentRepository;
    /*
    * 查询,根据id查询
    * */
    public Comment findById(Integer id){
        Optional<Comment>byId=commentRepository.findById(id);
        if(byId.isPresent()){
            return byId.get();
        }
        return null;
    }
            /*
            * 更新
            * */
            public int updateComment(Comment comment){
                int i = commentRepository.updateComment(comment.getAuthor(), comment.getId());
                return i;
            }
    /*
    * 删除
    * */
    public void deleteComment(Integer id){
        commentRepository.deleteById(id);
    }
}

6.创建控制类

编写Web访问层Controller文件CommentController,使用注入的CommentService实例对象编写对Comment评论数据的查询、修改和删除方法

@RestController
public class CommentController {
    @Autowired
    private CommentService commentService;
    /*
    * 查询
    * */
    @GetMapping("/get/{id}")
    //@@PathVariable("id")取得id赋值到getmapping中去
    public Comment findById(@PathVariable("id") Integer id){
        Comment comment=commentService.findById(id);
    return comment;
    }
    /*
     *更新
     *  */
    @GetMapping("/update/{id}/{author}")
    public int updateComment(@PathVariable("id") int id,@PathVariable("author") String author){
        Comment comment = commentService.findById(id);
        comment.setAuthor(author);
        int i = commentService.updateComment(comment);
        return i;
    }
    /*
     *删除
     * */
    @GetMapping("/delete/{id}")
    public void deleteById(@PathVariable("id")Integer id){
        commentService.deleteComment(id);
    }
}

7.编写全局配置文件连接数据库

spring.datasource.url=jdbc:mysql://localhost:3306/springboottest1?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=自己的数据库密码
#显示使用JPA进行数据库查询的sql语句
spring.jpa.show-sql=true

8.测试

在这里插入图片描述
这里会发现,如果没开启缓存,查询数据时,会重复查询,不利于服务器处理,特别是高并发情况下。

9.开启缓存

在启动类中添加缓存注解

@EnableCaching

在业务处理类(Service)中开启缓存处理

//将查询的id存放到缓存中
@Cacheable(cacheNames = "comment",unless = "#result==null")
//删除
@CacheEvict(cacheNames = "comment")
//更新
@CachePut(cacheNames = "comment",key = "#result.id")

代码如下(示例):

@Service
public class CommentService {
    @Autowired
    private CommentRepository commentRepository;
    /*
     * 查询,根据id查询
     * */
    //将查询的id存放到缓存中
    @Cacheable(cacheNames = "comment",unless = "#result==null")
    public Comment findById(Integer id){
        Optional<Comment> byId=commentRepository.findById(id);
        if(byId.isPresent()){
            return byId.get();
        }
        return null;
    }
    /*
     * 更新
     * */
//更新
    @CachePut(cacheNames = "comment",key = "#result.id")
    public int updateComment(Comment comment){
        int i = commentRepository.updateComment(comment.getAuthor(), comment.getId());
        return i;
    }
    /*
     * 删除
     * */
    //删除
    @CacheEvict(cacheNames = "comment")
    public void deleteComment(Integer id){
        commentRepository.deleteById(id);
    }
}

测试结果

在这里插入图片描述

会发现我们的数据被缓存了,多次访问仍然不会重复数据。

Spring Boot缓存注解介绍

1.@EnableCaching注解

@EnableCaching是由Spring框架提供的,Spring Boot框架对该注解进行了继承,该注解需要配置在类上(在Spring Boot中,通常配置在项目启动类上),用于开启基于注解的缓存支持。

2.@Cacheable注解

@Cacheable注解也是由Spring框架提供的,可以作用于类或方法(通常用在数据查询方法上),用于对方法结果进行缓存存储。

@Cacheable注解的执行顺序是,先进行缓存查询,如果为空则进行方法查询,并将结果进行缓存;如果缓存中有数据,不进行方法查询,而是直接使用缓存数据。

属性名说明
value/cacheNames指定缓存空间的名称,必配属性。这两个属性二选一使用
key指定缓存数据的key,默认使用方法参数值,可以使用SpEL表达式
keyGenerator指定缓存数据的key的生成器,与key属性二选一使用
cacheManager指定缓存管理器
cacheResolver指定缓存解析器,与cacheManager属性二选一使用
condition指定在符合某条件下,进行数据缓存
unless指定在符合某条件下,不进行数据缓存
sync指定是否使用异步缓存。默认false
3.@CachePut注解

@CachePut注解是由Spring框架提供的,可以作用于类或方法(通常用在数据更新方法上),该注解的作用是更新缓存数据。@CachePut注解的执行顺序是,先进行方法调用,然后将方法结果更新到缓存中。

@CachePut注解也提供了多个属性,这些属性与@Cacheable注解的属性完全相同。

4.@CacheEvict注解

@CacheEvict注解是由Spring框架提供的,可以作用于类或方法(通常用在数据删除方法上),该注解的作用是删除缓存数据。@CacheEvict注解的默认执行顺序是,先进行方法调用,然后将缓存进行清除。

@CacheEvict注解也提供了多个属性,这些属性与@Cacheable注解的属性基本相同,除此之外,还额外提供了两个特殊属性allEntries和beforeInvocation。

(1)allEntries属性
allEntries属性表示是否清除指定缓存空间中的所有缓存数据,默认值为false(即默认只删除指定key对应的缓存数据)。
(2)beforeInvocation属性
beforeInvocation属性表示是否在方法执行之前进行缓存清除,默认值为false(即默认在执行方法后再进行缓存清除)。

5.@Caching注解

@Caching注解用于针对复杂规则的数据缓存管理,可以作用于类或方法,在@Caching注解内部包含有Cacheable、put和evict三个属性,分别对应于@Cacheable、@CachePut和@CacheEvict三个注解。

@Caching(cacheable={@Cacheable(cacheNames ="comment",key = "#id")},
	put = {@CachePut(cacheNames = "comment",key = "#result.author")})
	public Comment getComment(int comment_id){
	return commentRepository.findById(comment_id).get();
}

6.@CacheConfig注解

@CacheConfig注解使用在类上,主要用于统筹管理类中所有使用@Cacheable、@CachePut和@CacheEvict注解标注方法中的公共属性,这些公共属性包括有cacheNames、keyGenerator、cacheManager和cacheResolver。

@CacheConfig(cacheNames = "comment")
@Service
public class CommentService {
    @Autowired
    private CommentRepository commentRepository;
    @Cacheable
    public Comment findById(int comment_id){
        Comment comment = commentRepository.findById(comment_id).get();
        return comment; }...}

基于注解的Redis缓存实现

Spring Boot支持的缓存组件

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(默认)
操作例子

1.添加Spring Data Redis依赖启动器

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

2.Redis服务连接配置

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

3.使用@Cacheable、@CachePut、@CacheEvict注解定制缓存管理

@Service
@Transactional
public class CommentService {
    @Autowired
    private CommentRepository commentRepository;
    /*
    * 查询,根据id查询
    * */
    //将查询的id存放到缓存中
    @Cacheable(cacheNames = "comment",unless = "#result==null")
    public Comment findById(int comment_id){
        Optional<Comment> optional = commentRepository.findById(comment_id);
        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }


    /*
            * 更新
            * */
    @CachePut(cacheNames = "comment",key = "#result.id")
    public Comment updateComment(Comment comment){
                int i = commentRepository.updateComment(comment.getAuthor(), comment.getId());
        Optional<Comment> byId = commentRepository.findById(comment.getId());
        if(byId.isPresent()){
            return byId.get();
        }
        return null;
            }
    /*
    * 删除
    * */
    @CacheEvict(cacheNames = "comment")
    public void deleteComment(Integer id){
        commentRepository.deleteById(id);
    }
}

4.基于注解的Redis查询缓存测试

@SpringBootApplication
//开启默认缓存注解
@EnableCaching

5.将缓存对象实现序列化

import javax.persistence.*;
import java.io.Serializable;
//该实体类与哪张表互相映射
@Entity(name = "t_comment")
//实现序列化接口
public class Comment implements Serializable {
    @Id//表示映射对应的主键
    //表示主键生成策略(自动增长)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String content;
    private String author;
    //指定映射的表字段名(表中的名字就是注解的name)
    @Column(name = "a_id")
    private Integer aId;

   }

6.基于注解的Redis缓存查询测试
查询结果为一条,反复查询依然调用Redis缓存空间的
在这里插入图片描述
7.基于注解的Redis缓存更新测试

在这里插入图片描述

8.基于注解的Redis缓存删除测试
在这里插入图片描述

基于API的Redis缓存实现

**使用Redis API **进行业务数据缓存管理

编写一个进行业务处理的类ApiCommentService,使用@Autowired注解注入Redis API中常用的RedisTemplate(类似于Java基础API中的JdbcTemplate);然后在数据查询、修改和删除三个方法中,根据业务需求分别进行数据缓存查询、缓存存储、缓存更新和缓存删除。同时,Comment数据对应缓存管理的key值都手动设置了一个前缀“comment_”,这是针对不同业务数据进行缓存管理设置的唯一key,避免与其他业务缓存数据的key重复。

@Service
@Transactional
public class ApiCommentService {
    @Autowired
    private CommentRepository commentRepository;
    @Autowired
    private RedisTemplate redisTemplate;
    /*
    * 查询方法
    * */
    public Comment findById(Integer id){
        Object o = redisTemplate.opsForValue().get("comment_" + id);
        if (o!=null){
            //缓存有数据
            return (Comment)o;
        }else {
            Optional<Comment> byId = commentRepository.findById(id);
            if(byId.isPresent()){
                Comment comment = byId.get();
                redisTemplate.opsForValue().set("comment_"+id,comment,1, TimeUnit.DAYS);
                return comment;
            }
            return null;
        }
    }
    /*
     * 更新方法
     * */
    public Comment updateComment(Comment comment){
        commentRepository.updateComment(comment.getAuthor(), comment.getaId());
        redisTemplate.opsForValue().set("comment_"+comment.getId(),comment);
        return comment;
    }

    /*
     * 删除方法
     * */
    public void deleteComment(int comment_id){
        commentRepository.deleteById(comment_id);
        redisTemplate.delete("comment_"+comment_id);
    }

}
② 编写Web访问层Controller文件ApiCommentController

在类上加入了@RequestMapping(“/api”)注解用于窄化请求,并通过@Autowired注解注入了新编写的ApiCommentService实例对象,然后调用ApiCommentService中的相关方法进行数据查询、修改和删除。

@RestController
@RequestMapping("Api")
public class ApiCommentController {
    @Autowired
    private CommentService commentService;
    @Autowired
    private ApiCommentService apiCommentService;
    /*
    * 查询
    * */
    @GetMapping("/get/{id}")
    //@@PathVariable("id")取得id赋值到getmapping中去
    public Comment findById(@PathVariable("id") Integer id){
        Comment comment=apiCommentService.findById(id);
    return comment;
    }
    /*
     *更新
     *  */
    @GetMapping("/update/{id}/{author}")
    public Comment updateComment(@PathVariable("id") int id,@PathVariable("author") String author){
        Comment comment = apiCommentService.findById(id);
        comment.setAuthor(author);
        Comment comment1 = apiCommentService.updateComment(comment);
        return comment1;
    }
    /*
     *删除
     * */
    @GetMapping("/delete/{id}")
    public void deleteById(@PathVariable("id")Integer id){
        apiCommentService.deleteComment(id);
    }
}
③基于API的Redis缓存实现的相关配置

1.基于API的Redis缓存实现不需要@EnableCaching注解开启基于注解的缓存支持。

2.基于API的Redis缓存实现需要在Spring Boot项目的pom.xml文件中引入Redis依赖启动器,并在配置文件中进行Redis服务连接配置,同时将进行数据存储的Comment实体类实现序列化接口。

缓存测试与基于注解的Redis缓存实现的测试完全一样。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值