SpringBoot內置Ehcache緩存,你知道嗎?

平時使用的緩存一般都是 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";
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章