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