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

猜你喜欢

转载自blog.csdn.net/qq_33371766/article/details/106968526
今日推荐