# springboot_cache **Repository Path**: gitsunan/springboot_cache ## Basic Information - **Project Name**: springboot_cache - **Description**: springBoot注解缓存开发 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-11-17 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README **目录** * 一:springBoot开启缓存注解 * 二:常用缓存注解 * 三:使用实例 * 四:总结 # 一:springBoot开启注解 # ## 1.1:搭建springBoot环境 ## 在idea中,搭建一个springboot是很简单easy的。接下来我简单说一下步骤: File->new->projiect->Spring Initializer->next->named->web(选中)->Finish->new Window ## 1.2:开始缓存 ## @SpringBootApplication @EnableAutoConfiguration @EnableCaching public 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),可以使用这一个注解来包含上面的所有的注解,看源码如下 ![输入图片说明](https://images.gitee.com/uploads/images/2019/1117/232109_7d4a58d9_2249566.png "屏幕截图.png") 上面的注解总结如下表格: ![输入图片说明](https://images.gitee.com/uploads/images/2019/1117/232202_99ad948e_2249566.png "屏幕截图.png") # 三:使用实例 # ## 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=InnoDB DEFAULT CHARACTER SET=gbk COLLATE=gbk_chinese_ci AUTO_INCREMENT=11 ROW_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();         }     } } # 四:总结 # 本篇博客介绍了springBoot中缓存的一些使用方法,如何在开发中使用缓存?怎样合理的使用都是值得我们学习的地方,缓存能大大提升程序的响应速度,提升用户体验,不过它适用的场景也是读多写少的业务场景,如果数据频繁修改,缓存将会失去意义,每次还是执行的数据库操作!如何使用好它,还有更高效的方式,比如使用redis\\memoryCache等专业组件,本篇博客只是探讨的spring的注解缓存,相对来说比较简单。希望起到抛砖引玉的作用,在以后博客中,我将介绍redis如何搭建集群来实现缓存!