平時使用的緩存一般都是 redis、mongoDB 等等,SpringBoot 內置集成了 EhCache,EhCache是一個比較成熟的Java緩存框架,最早從hibernate發展而來, 是進程中的緩存系統,它提供了用內存,磁盤文件存儲,以及分佈式存儲方式等多種靈活的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.2.2.RELEASE</version>
<relativePath />
</parent>
<groupId>com.yellow.etc</groupId>
<artifactId>SpringBoot-cache</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>SpringBoot-cache</name>
<description>SpringBoot默認Ehcache緩存</description>
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--開啓 cache 緩存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- ehcache 緩存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"
updateCheck="false">
<!--
diskStore:爲緩存路徑,ehcache分爲內存和磁盤 2級,此屬性定義磁盤的緩存位置
user.home - 用戶主目錄
user.dir - 用戶當前工作目錄
java.io.tmpdir - 默認臨時文件路徑
-->
<diskStore path="java.io.tmpdir/Tmp_EhCache"/>
<!--
name:緩存名稱。
maxElementsInMemory:緩存最大數目
maxElementsOnDisk:硬盤最大緩存個數。
eternal:對象是否永久有效,一但設置了,timeout將不起作用。
overflowToDisk:是否保存到磁盤,當系統宕機時
timeToIdleSeconds:設置對象在失效前的允許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。
timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
diskPersistent:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩衝區。
diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置爲FIFO(先進先出)或是LFU(較少使用)。
clearOnFlush:內存數量最大時是否清除。
memoryStoreEvictionPolicy:可選策略有:LRU(最近最少使用,默認策略)、FIFO(先進先出)、LFU(最少訪問次數)。
FIFO,first in first out,這個是大家最熟的,先進先出。
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一點就是講一直以來最少被使用的。如上面所講,緩存的元素有一個hit屬性,hit值最小的將會被清出緩存。
LRU,Least Recently Used,最近最少使用的,緩存的元素有一個時間戳,當緩存容量滿了,而又需要騰出地方來緩存新的元素的時候,那麼現有緩存元素中時間戳離當前時間最遠的元素將被清出緩存。
-->
<defaultCache eternal="false" maxElementsInMemory="5000" overflowToDisk="false"
diskPersistent="false" timeToIdleSeconds="120" timeToLiveSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<cache name="baseCache" maxElementsInMemory="10000"
maxElementsOnDisk="100000"/>
</ehcache>
啓動類開啓緩存
@SpringBootApplication
@EnableCaching
public class SpringBootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootCacheApplication.class, args);
}
}
Mapper
在 Mapper 中要配置使用的緩存名,在開啓緩存的方法上也要打上註解,這裏就只寫了一個簡單的查詢方法。
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import com.yellow.etc.entity.User;
@Mapper
@CacheConfig(cacheNames = "baseCache")
public interface UserMapper {
@Cacheable
@Select("SELECT * FROM tb_user WHERE id = #{id}")
User getUser(@Param("id") int id);
}
測試
我們通過 Controller 方法調用查詢用戶信息,第一次查詢的用戶信息如下。
調用成功後,我們去修改數據庫信息,再次調用方法。
再次調用信息還是 里斯,說明這次走的不是數據庫,而是從緩存拿取數據。
更新緩存不生效問題
當我們修改數據時,希望緩存中數據也要發生變化,但是在 EhCache 中,普通的更新方法不會修改緩存中的信息。
編寫一個更新方法,調用一下,修改用戶信息,執行成功。
再次調用查詢方法,發現用戶數據沒有發生變化,但是數據庫數據已經被修改,說明還是從緩存中獲取數據,而緩存數據沒有被更新。
解決
引入 SpringBoot 集成的 CacheManager,每次更新數據後清除緩存。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yellow.etc.entity.User;
import com.yellow.etc.service.UserService;
@RestController
public class HelloController {
@Autowired
private UserService userService;
@Autowired
private CacheManager cacheManager;
@GetMapping("get")
public String getUser(int id) {
User user = userService.getUser(id);
return user.toString();
}
@GetMapping("update")
public String update(int id, String name) {
userService.update(id, name);
// 清除緩存
Cache cache = cacheManager.getCache("baseCache");
cache.clear();
return "ok";
}
}