点击上方“Java专栏”,选择“置顶或者星标”

第一时间阅读精彩文章!

☞ 程序员进阶必备资源免费送「21种技术方向!」 点击查看☜

作者:Yrion

cnblogs.com/wyq178/p/9840985.html

前言:缓存在开发中是一个必不可少的优化点,近期在公司的项目重构中,关于缓存优化了很多点,比如在加载一些数据比较多的场景中,会大量使用缓存机制提高接口响应速度,间接提升用户体验。

关于缓存,很多人对它都是既爱又恨,爱它的是:它能大幅提升响应效率,恨的是它如果处理不好,没有用好比如LRU这种策略,没有及时更新数据库的数据就会导致数据产生滞后,进而产生用户的误读,或者疑惑。

这是很严重的一个问题,比如我在公司和某家公司(国内的一线旅游开发公司)的对接的时候,线上总是出现我们推送接口数据但是网站的数据产生滞后的现象,询问对方的技术人员,告诉我们是缓存的问题,只要删除缓存就没事了,我只能无奈…所以如何处理好缓存,对我们开发人员来说是一个很棘手的问题。不过关于这一切,springboot已经提供给我们很便捷的开发工具!

本篇博客就来探索springBoot的缓存注解如何使用!

本篇博客的目录

  • springBoot开启缓存注解

  • 常用缓存注解

  • 使用实例

  • 总结

一:springBoot开启注解

1.1:搭建springBoot环境

在idea中,搭建一个springboot是很简单easy的。接下来我简单说一下步骤:

File->new->projiect->Spring Initializer->next->named->web(选中)->Finish->new Window

1.2:开始缓存

@SpringBootApplication@EnableAutoConfiguration@EnableCachingpublic class SpringbootcacheApplication {

    public static void main(String[] args) {        SpringApplication.run(SpringbootcacheApplication.class, args);    }}

主要是@EnableCaching用于开启缓存注解的驱动,否则后面使用的缓存都是无效的!

二:常用缓存注解

2.1:@CacheConfig

这个注解的的主要作用就是全局配置缓存,比如配置缓存的名字(cacheNames),只需要在类上配置一次,下面的方法就默认以全局配置为主,不需要二次配置,节省了部分代码。

2.2:@Cacheable

这个注解是最重要的,主要实现的功能再进行一个读操作的时候。就是先从缓存中查询,如果查找不到,就会走数据库的执行方法,这是缓存的注解最重要的一个方法,基本上我们的所有缓存实现都要依赖于它。它具有的属性为cacheNames:缓存名字,condtion:缓存的条件,unless:不缓存的条件。可以指定SPEL表达式来实现,也可以指定缓存的key,缓存的内部实现一般都是key,value形式,类似于一个Map(实际上cacheable的缓存的底层实现就是concurrenHashMap),指定了key,那么缓存就会以key作为键,以方法的返回结果作为值进行映射。

2.3:@CacheEvict

这个注解主要是配合@Cacheable一起使用的,它的主要作用就是清除缓存,当方法进行一些更新、删除操作的时候,这个时候就要删除缓存。如果不删除缓存,就会出现读取不到最新缓存的情况,拿到的数据都是过期的。它可以指定缓存的key和conditon,它有一个重要的属性叫做allEntries默认是false,也可以指定为true,主要作用就是清除所有的缓存,而不以指定的key为主。

2.4:@CachePut

这个注解它总是会把数据缓存,而不会去每次做检查它是否存在,相比之下它的使用场景就比较少,毕竟我们希望并不是每次都把所有的数据都给查出来,我们还是希望能找到缓存的数据,直接返回,这样能提升我们的软件效率。

2.5:@cache

这个注解它是上面的注解的综合体,包含上面的三个注解(cacheable、cachePut、CacheEvict),可以使用这一个注解来包含上面的所有的注解,看源码如下

上面的注解总结如下表格:

三:使用实例

3.1:建立数据库

我们来新建一个表,含义为文章,下面的示例将会在这张表中进行操作,所使用的框架为SSM+springboot

CREATE TABLE Artile (`id`  int(11) NOT NULL AUTO_INCREMENT ,`title`  varchar(30) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL ,`author`  varchar(30) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL ,`content`  mediumtext CHARACTER SET gbk COLLATE gbk_chinese_ci NULL ,`file_name`  varchar(30) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL ,`state`  smallint(2) NULL DEFAULT 1 COMMENT '状态' ,PRIMARY KEY (`id`))ENGINE=InnoDBDEFAULT CHARACTER SET=gbk COLLATE=gbk_chinese_ciAUTO_INCREMENT=11ROW_FORMAT=COMPACT;

3.2:Mapper层

主要就是对Article进行增删改查的业务操作,映射到具体的xml的sql里,然后用service去调用

public interface ArticleMapper {

    /**     * 插入一篇文章     * @param title     * @param author     * @param content     * @param fileName     * @return     */    public Integer addArticle(@Param("title") String  title,@Param("author")String author,                              @Param("content")String content,@Param("fileName")String fileName);    /**     * 根据id获取文章     * @param id     * @return     */    public Article getArticleById(@Param("id") Integer id);

    /**     * 更新content     * @param content     */    public Integer updateContentById(@Param("content")String content,@Param("id")Integer id);

    /**     * 根据id删除文章     * @param id     * @return     */    public Integer removeArticleById(@Param("id")Integer id);

    /**     * 获得上一次插入的id     * @return     */    public Integer getLastInertId();

}

3.3:service层

主要需要注意的是我们上述讲述的缓存注解都是基于service层(不能放在contoller和dao层),首先我们在类上配置一个CacheConfig,然后配置一个cacheNames,那么下面的方法都是以这个缓存名字作为默认值,他们的缓存名字都是这个,不必进行额外的配置。当进行select查询方法的时候,我们配置上@Cacheable,并指定key,这样除了第一次之外,我们都会把结果缓存起来,以后的结果都会把这个缓存直接返回。而当进行更新数据(删除或者更新操作)的时候,使用@CacheEvict来清除缓存,防止调用@Cacheabel的时候没有更新缓存

@Service@CacheConfig(cacheNames = "articleCache")public class ArticleService {

    private AtomicInteger count =new AtomicInteger(0);

    @Autowired    private ArticleMapper articleMapper;

    /**     * 增加一篇文章 每次就进行缓存     * @return     */    @CachePut    public Integer addArticle(Article article){        Integer result = articleMapper.addArticle(article.getTitle(), article.getAuthor(), article.getContent(), article.getFileName());        if (result>0) {            Integer lastInertId = articleMapper.getLastInertId();            System.out.println("--执行增加操作--id:" + lastInertId);        }        return result;    }

    /**     * 获取文章  以传入的id为键,当state为0的时候不进行缓存     * @param id 文章id     * @return     */    @Cacheable(key = "#id",unless = "#result.state==0")    public Article getArticle(Integer id) {        try {            //模拟耗时操作            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }        final Article artcile = articleMapper.getArticleById(id);        System.out.println("--执行数据库查询操作"+count.incrementAndGet()+"次"+"id:"+id);        return artcile;    }

    /**     * 通过id更新内容 清除以id作为键的缓存     *     * @param id     * @return     */    @CacheEvict(key = "#id")    public Integer updateContentById(String contetnt, Integer id) {        Integer result = articleMapper.updateContentById(contetnt, id);        System.out.println("--执行更新操作id:--"+id);        return result;    }

    /**     * 通过id移除文章     * @param id  清除以id作为键的缓存     * @return     */    @CacheEvict(key = "#id")    public Integer removeArticleById(Integer id){        final Integer result = articleMapper.removeArticleById(id);        System.out.println("执行删除操作,id:"+id);        return result;    }

}

3.4:controller层

主要是接受客户端的请求,我们配置了@RestController表示它是一个rest风格的应用程序,在收到add请求会增加一条数据,get请求会查询一条数据,resh会更新一条数据,rem会删除一条数据

@RestController@ComponentScan(basePackages = {"com.wyq.controller", "com.wyq.service"})@MapperScan(basePackages = {"com.wyq.dao"})public class ArticleController {

    @Autowired    private ArticleService articleService;

    @Autowired    ArticleMapper articleMapper;

    @PostMapping("/add")    public ResultVo addArticle(@RequestBody Article article) {

        System.out.println(article.toString());        Integer result = articleService.addArticle(article);

        if (result >= 0) {            return ResultVo.success(result);        }        return ResultVo.fail();    }

    @GetMapping("/get")    public ResultVo getArticle(@RequestParam("id") Integer id) {

        Long start = System.currentTimeMillis();        Article article = articleService.getArticle(id);        Long end = System.currentTimeMillis();        System.out.println("耗时:"+(end-start));

        if (null != article)            return ResultVo.success(article);        return ResultVo.fail();    }

    /**     * 更新一篇文章     *     * @param contetnt     * @param id     * @return     */    @GetMapping("/resh")    public ResultVo update(@RequestParam("content") String contetnt, @RequestParam("id") Integer id) {        final Integer result = articleService.updateContentById(contetnt, id);        if (result > 0) {            return ResultVo.success(result);        } else {            return ResultVo.fail();        }    }

    /**     * 删除一篇文章     *     * @param id     * @return     */    @GetMapping("/rem")    public ResultVo remove(@RequestParam("id") Integer id) {

        final Integer result = articleService.removeArticleById(id);        if (result > 0) {            return ResultVo.success(result);        } else {            return ResultVo.fail();        }    }

}

3.5:测试

这里使用postman模拟接口请求

3.5.1:首先我们来增加一篇文章:请求add接口:

后台返回表示成功:

我看到后台数据库已经插入了数据,它的id是11

3.5.2:执行查询操作

在查询操作中,getArticle,我使用线程睡眠的方式,模拟了5秒的时间来处理耗时性业务,第一次请求肯定会查询数据库,理论上第二次请求,将会走缓存,我们来测试一下:首先执行查询操作

接口响应成功,再看一下后台打印:表示执行了一次查询操作,耗时5078秒

好,重点来了,我们再次请求接口看看会返回什么?理论上,将不会走数据库执行操作,并且耗时会大大减少:与上面的比对,这次没有打印执行数据库查询操作,证明没有走数据库,并且耗时只有5ms,成功了!缓存发挥作用,从5078秒减小到5秒!大大提升了响应速度,哈哈!

3.5.3:更新操作

当我们进行修改操作的时候,我们希望缓存的数据被清空:看接口返回值成功了,再看数据库

后台控制台打印:

--执行更新操作id:--11

趁热打铁,我们再次请求三次查询接口,看看会返回什么?每次都会返回这样的结果,但是我的直观感受就是第一次最慢,第二次、第三次返回都很快

再看看后台打印了什么?执行id为11的数据库查询操作,这是因为缓存被清空了,所以它又走数据库了(获得最新数据),然后后面的查询都会走缓存!很明显,实验成功!

3.5.4:删除操作

同理,在删除操作中,执行了一次删除,那么缓存也会被清空,查询的时候会再次走数据库,这里就不给具体实验效果了,如果需要的同学,可以把代码下载下来,自己测试一下就知道了。

四:总结

本篇博客介绍了springBoot中缓存的一些使用方法,如何在开发中使用缓存?怎样合理的使用都是值得我们学习的地方,缓存能大大提升程序的响应速度,提升用户体验,不过它适用的场景也是读多写少的业务场景,如果数据频繁修改,缓存将会失去意义,每次还是执行的数据库操作!

如何使用好它,还有更高效的方式,比如使用redis\memoryCache等专业组件,本篇博客只是探讨的spring的注解缓存,相对来说比较简单。


以上,便是今天的分享,希望大家喜欢,觉得内容不错的,欢迎点击「在看」支持,谢谢各位

喜欢文章,点个在看 

springboot 插入返回id_实战SpringBoot缓存开发相关推荐

  1. springboot 插入返回id_Spring Boot实现分布式微服务开发实战系列(七)

    今天已经进入第七讲了,整个微服务架构的搭建工作也基本完成.那到目前为止究竟使用了那些技术及实现了什么功能呢?我们先回顾一下. 使用的技术:SpringBoot.Dubbo.Zookeeper.Redi ...

  2. springboot怎么返回404_自定义SpringBoot REST API 404返回信息

    自定义SpringBoot REST API 404返回信息 在访问SpringBoot的REST接口时,如果请求的地址不存在Spring会返回如下JSON信息 { "timestamp&q ...

  3. c# mysql 插入返回id_在C#中,mysql插入一条数据时,怎么同时把这条数据的主键返回?...

    展开全部 可以尝试使用  last_insert_id()  来获取一下看看. 下面是 仅仅在 mysql 下面的测试例子: mysql> CREATE TABLE test_create_ta ...

  4. 详细SpringBoot教程之缓存开发

    写在前面 这一系列的博文初步都定下来包括SpringBoot介绍.入门.配置.日志相关.web开发.数据访问.结合docker.缓存.消息队列.检索.任务安全.分布式等等一系列的博文,工作量很大,是个 ...

  5. 视频教程-SpringBoot实战教程:SpringBoot入门及前后端分离项目开发-Java

    SpringBoot实战教程:SpringBoot入门及前后端分离项目开发 十三,CSDN达人课课程作者,CSDN 博客作者,现就职于某网络科技公司任职高级 Java 开发工程师,13blog.sit ...

  6. springboot+vue项目大型实战(一)后端开发

    源码下载地址!!!点我 数据库创建表 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;-- ---------------------------- -- ...

  7. SpringBoot交友APP项目实战(详细介绍+案例源码) - 9.小视频(SpringCache缓存)

    有人相爱,有人跳海 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 ...

  8. SpringBoot后端数据校验实战

    本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:SpringBoot后端数据校验实战 一般我们会在Controller的接口中对前端传递的参数做数据校验,这是一个后端开发人员的基本素养 在Sp ...

  9. SpringBoot+MyBatis+MYSQL项目实战六(新增收货地址)

    SpringBoot+MyBatis+MYSQL项目实战六(新增收货地址) 项目源码地址:电脑商城实战 点击新增收货地址 一:新增收货地址--数据表的创建 CREATE TABLE t_address ...

最新文章

  1. python编程自学能学会吗-自学Python会有什么困难?老男孩自学python编程
  2. elasticsearch 第五篇(文档操作接口)
  3. 服务器数据缓存文件实现,跨域与缓存
  4. java实现可视化报表_如何在Power BI中记录报表可视化?
  5. MySQL--3--mysqldump备份策略
  6. CodeForce 168 C——Wizards and Trolleybuses
  7. CSS3边框图片、边框阴影、文本阴影
  8. CodeForces615A-Bulbs-模拟
  9. 简单的java恶搞小病毒_恶搞电脑病毒代码有哪些
  10. 韩顺平_JAVA_视频教程_下载(打开迅雷,直接复制链接地址即可下载)
  11. windows宽带连接(校园网)自动连接脚本代码
  12. qt4.8.7 2016年4月18日 error reading collection file qthelpcollection cannot load sql
  13. python 正则表达式爬图片_利用python正则表达式爬取图片
  14. Cascade EF-GAN: 局部聚焦渐进式面部表情编辑
  15. 使用云服务器ECS搭建DoH服务的开发实践
  16. Apple Color Emoji打开
  17. Java的长整型Long/long后面的数字什么情况下必须加L?
  18. php票据打印模板,PHP实现多条采购单据界面
  19. java字符串用0X0F分割_微信公众帐号开发教程第4篇-----开发模式启用及接口配置Java...
  20. 软件构造——浅谈正则表达式

热门文章

  1. Markdown:数学公式练习(3)
  2. Ganglia集群监控系统搭建
  3. 为什么很多人说 Java 不适合编写桌面应用?
  4. 科大星云诗社动态20210303
  5. 涵盖 14 大主题!最完整的 Python 学习实例集来了!
  6. 台湾大学林轩田机器学习技法课程学习笔记10 -- Random Forest
  7. java获取异常的数据_Java(8题):异常,通过try catch进行处理,登录,商品,使用jdbc进行读取,详细图析...
  8. 命令行设置dns_网络感叹号dns未响应
  9. VTK修炼之道30:图像重采样_降采样和升采样技术
  10. 找出存在性能问题的sql语句