pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http:///POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http:///POM/4.0.0 https:///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 这个注解它是上面的注解的综合体,包