Springboot使用MybatisPlus實現Cache緩存

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.frank</groupId>
    <artifactId>cache</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cache-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

spring.datasource.url= jdbc:mysql://localhost:3306/cache-db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username= root
spring.datasource.password= 123456
spring.datasource.driver-class-name= com.mysql.jdbc.Driver


mybatis-plus.mapper-locations= classpath:mapper/*Mapper.xml
ArticleController
package com.frank.cache.controller;

import com.frank.cache.entity.Article;
import com.frank.cache.entity.ResultVo;
import com.frank.cache.mapper.ArticleMapper;
import com.frank.cache.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 小石潭記
 * @date 2020/6/26 11:30
 * @Description: ${todo}
 */
@RestController
@Slf4j
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @Autowired
    ArticleMapper articleMapper;

    /**
     * 添加文章
     */
    @PostMapping("/add")
    public ResultVo addArticle(@RequestBody Article article) {
        log.info(article.toString());
        Integer result = articleService.addArticle(article);
        if (result >= 0) {
            return ResultVo.success(article);
        }
        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();
        log.info("耗時:"+ (end-start));
        if (null != article)
            return ResultVo.success(article);
        return ResultVo.fail();
    }

    @GetMapping("/getAll")
    public ResultVo getAllArticle() {
        Long start = System.currentTimeMillis();
        List<Article> articles = articleService.getAllArticles();
        Long end = System.currentTimeMillis();
        log.info("耗時:"+(end-start));
        if (null != articles) {
            return ResultVo.success(articles);
        }
        return ResultVo.fail();
    }

    /**
     * 更新一篇文章
     */
    @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();
        }
    }

    /**
     * 刪除一篇文章
     */
    @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();
        }
    }
}
Article
package com.frank.cache.entity;

import lombok.Data;

/**
 * @author 小石潭記
 * @date 2020/6/26 11:20
 * @Description: ${todo}
 */
@Data
public class Article {
    private int id;
    private String title;
    private String content;
    private String author;
    private String fileName;
    private String state;
}
ResultVo
package com.frank.cache.entity;

import lombok.Data;

/**
 * @author 小石潭記
 * @date 2020/6/26 11:32
 * @Description: ${todo}
 */
@Data
public class ResultVo {
    private int code;
    private String message;
    private Object data;

    public static ResultVo success(Object object){
        ResultVo resultVo = new ResultVo();
        resultVo.setCode(200);
        resultVo.setMessage("success");
        resultVo.setData(object);
        return resultVo;
    }

    public static ResultVo fail(){
        ResultVo resultVo = new ResultVo();
        resultVo.setCode(404);
        resultVo.setMessage("fail");
        resultVo.setData(null);
        return resultVo;
    }
}
ArticleMapper
package com.frank.cache.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.frank.cache.entity.Article;

import java.util.List;

/**
 * @author 小石潭記
 * @date 2020/6/26 11:23
 * @Description: ${todo}
 */
public interface ArticleMapper extends BaseMapper<Article> {
    /**
     * 自定義sql查詢
     */
    List<Article> getAllArticles();
}
ArticleService
package com.frank.cache.service;

import com.frank.cache.entity.Article;
import com.frank.cache.mapper.ArticleMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 小石潭記
 * @date 2020/6/26 11:27
 * @Description: service層引入cache緩存
 */
@Service
@CacheConfig(cacheNames = "articleCache")
@Slf4j
public class ArticleService {

    private AtomicInteger count =new AtomicInteger(0);

    @Autowired
    private ArticleMapper articleMapper;

    /**
     * 增加一篇文章 每次就進行緩存
     * @return
     */
    @CachePut
    public Integer addArticle(Article article){
        int insert = articleMapper.insert(article);
        if (insert>0) {
            return insert;
        }
        return null;
    }

    /**
     * 獲取文章  以傳入的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();
        }
        Article article = articleMapper.selectById(id);
        log.info("--執行數據庫查詢操作"+count.incrementAndGet()+"次"+"id:"+id);
        return article;
    }

    /**
     * 自定義的sql方法
     * @return
     */
    @Cacheable()
    public List<Article> getAllArticles() {
        try {
            //模擬耗時操作
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<Article> allArticles = articleMapper.getAllArticles();
        return allArticles;
    }

    /**
     * 通過id更新內容 清除以id作爲鍵的緩存
     *
     * @param id
     * @return
     */
    @CacheEvict(key = "#id")
    public Integer updateContentById(String content, Integer id) {
        Article article = articleMapper.selectById(id);
        article.setContent(content);
        int result = articleMapper.updateById(article);
        log.info("--執行更新操作id:--"+id);
        return result;
    }

    /**
     * 通過id移除文章
     * @param id  清除以id作爲鍵的緩存
     * @return
     */
    @CacheEvict(key = "#id")
    public Integer removeArticleById(Integer id){
        int result = articleMapper.deleteById(id);
        log.info("執行刪除操作,id:"+id);
        return result;
    }
}
CacheDemoApplication
package com.frank.cache;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableCaching
@MapperScan(basePackages = {"com.frank.cache"})
public class CacheDemoApplication {

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

}

ArticleMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
<mapper namespace="com.frank.cache.mapper.ArticleMapper">
    <select id="getAllArticles" resultType="com.frank.cache.entity.Article">
        select * from article
    </select>

    <!--resultMap-->
    <!--如果返回map、list需要這樣映射一下-->
    <resultMap id="myArticle" type="com.frank.cache.entity.Article">
        <id column="id" property="id" />
        <result column="title" property="title" />
        <result column="content" property="content" />
        <result column="author" property="author" />
        <result column="fileName" property="file_name" />
        <result column="state" property="state" />
    </resultMap>

</mapper>

db.sql

CREATE TABLE Article
(
  `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;
# Cache Started

* @CacheConfig
這個註解的的主要作用就是全局配置緩存,比如配置緩存的名字(cacheNames),只需要在類上配置一次,下面的方法就默認以全局配置爲主,不需要二次配置,節省了部分代碼。

* @Cacheable
這個註解是最重要的,主要實現的功能再進行一個讀操作的時候。就是先從緩存中查詢,如果查找不到,就會走數據庫的執行方法,這是緩存的註解最重要的一個方法,基本上我們的所有緩存實現都要依賴於它。它具有的屬性爲cacheNames:緩存名字,condtion:緩存的條件,unless:不緩存的條件。可以指定SPEL表達式來實現,也可以指定緩存的key,緩存的內部實現一般都是key,value形式,類似於一個Map(實際上cacheable的緩存的底層實現就是concurrenHashMap),指定了key,那麼緩存就會以key作爲鍵,以方法的返回結果作爲值進行映射。

* @CacheEvict
這個註解主要是配合@Cacheable一起使用的,它的主要作用就是清除緩存,當方法進行一些更新、刪除操作的時候,這個時候就要刪除緩存。如果不刪除緩存,就會出現讀取不到最新緩存的情況,拿到的數據都是過期的。它可以指定緩存的key和conditon,它有一個重要的屬性叫做allEntries默認是false,也可以指定爲true,主要作用就是清除所有的緩存,而不以指定的key爲主。

* @CachePut
這個註解它總是會把數據緩存,而不會去每次做檢查它是否存在,相比之下它的使用場景就比較少,畢竟我們希望並不是每次都把所有的數據都給查出來,我們還是希望能找到緩存的數據,直接返回,這樣能提升我們的軟件效率。

* @cache
這個註解它是上面的註解的綜合體,包含上面的三個註解(cacheable、cachePut、CacheEvict),可以使用這一個註解來包含上面的所有的註解。

測試:
http://localhost:8080/add   POST
{
   "title": "老人與海",
   "content": "老人的線緊牽,愛學習的心,永不變.",
   "author": "海明威",
   "fileName": "老人與海",
   "state": "1"
}

http://localhost:8080/get?id=1  第一次查詢數據庫,耗時5028,繼續訪問該接口則直接讀取緩存,耗時非常短。


http://localhost:8080/getAll

http://localhost:8080/resh?id=1&content=一本很有意思的書籍

http://localhost:8080/rem?id=2

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章