一、为什么要使用缓存
什么是缓存,我们为什么要使用缓存?缓存实际上是为了减轻数据库服务器的负载,使用缓存,我们可以将一些常用的数据放入缓存,因为这些数据经常性的使用,大大增加了服务器的负载,但是当放入缓存后,在使用这些数据的时候,首先会从缓存中查找,如果缓存中有就读取,不会再到数据库中查找,如果缓存中没有,才会到数据库中查询,在这里,需要注意的是,ehcache的是将数据放入jvm内存中,也就是说当次缓存在本次服务器启动期间有效,下次服务器启动将会失效。
二、EhCache简介
1、基本介绍
EhCache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级 容器。可以和大部分Java项目无缝整合,例如:Hibernate中的缓存就是基于EhCache实现 的。 EhCache支持内存和磁盘存储,默认存储在内存中,如内存不够时把缓存数据同步到磁 盘中。EhCache支持基于Filter的Cache实现,也支持Gzip压缩算法。
2、主要的特性
EhCache直接在JVM虚拟机中缓存,速度快,效率高;
EhCache缺点是缓存共享麻烦,集群分布式应用使用不方便;
可以单独使用,一般在第三方库中被用到的比较多(如mybatis、shiro等)ehcache 对分布式支持不够好,多个节点不能同步,通常和redis一块使用;
3、ehcache 和 redis 比较
ehcache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
redis是通过socket访问到缓存服务,效率比Ehcache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。如果是单个应用或者对缓存访问要求很高的应用,用ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。
ehcache也有缓存共享方案,不过是通过RMI或者Jgroup多播方式进行广播缓存通知更新,缓存共享复杂,维护不方便;简单的共享可以,但是涉及到缓存恢复,大数据缓存,则不合适。
三、入门案例
1、添加依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.6.11</version>
</dependency>
2、编写ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!--
磁盘的缓存位置
磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存
path:指定在硬盘上存储对象的路径
path可以配置的目录有:
user.home(用户的家目录)
user.dir(用户当前的工作目录)
java.io.tmpdir(默认的临时目录)
ehcache.disk.store.dir(ehcache的配置目录)
绝对路径(如:d:\\ehcache)
查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir");
-->
<diskStore path="D:\JAVA\Project\EhCache"/>
<!--默认缓存-->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<!--helloworld 缓存-->
<cache name="HelloWorldCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="5"
timeToLiveSeconds="5"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
<!--
defaultCache:默认缓存策略,当 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,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳
离当前时间最远的元素将被清出缓存。
-->
</ehcache>
3、编写测试方法
public static void main(String[] args) {
//获取编译目录下的资源的流对象
InputStream input = TestEH.class.getClassLoader().getResourceAsStream("EhCache/ehcache.xml");
//获取 EhCache 的缓存管理对象
CacheManager cacheManager = new CacheManager(input);
//获取缓存对象
Cache cache = cacheManager.getCache("HelloWorldCache");
//创建缓存数据
Element element = new Element("name","zhang3");
//存入缓存
cache.put(element);
//从缓存中取出
Element element1 = cache.get("name");
System.out.println(element1.getObjectValue());
}
四、springboot集成EhCache
1、添加springboot 配置(application.yml)
spring:
cache:
type: ehcache
ehcache:
config: classpath:ehcache.xml
2、pring boot启动类开启缓存注解
@EnableCaching
3、EhCache工具类
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Ehcache工具类
*
* @Author syh
* @Date 2022/11/16 11:28
*/
@Component
public class EhcacheUtils {
@Autowired
private CacheManager cacheManager;
/**
* 获取Ehcache对象
*
* @param cacheName 缓存策略
* @return Cache
*/
public Cache getEhcache(String cacheName){
return cacheManager.getCache(cacheName);
}
/**
* 获取缓存
*
* @param cacheName xml中配置的缓存策略
* @param key 键
* @return Object
*/
public Object getCache(String cacheName,String key){
Cache cache = cacheManager.getCache(cacheName);
if(cache==null){
return null;
}
return cache.get(key).getObjectValue();
}
/**
* 保存一个缓存数据,若使用的缓存策略不存在则创建一个新的缓存
*
* @param cacheName xml中配置的缓存策略的名字
* @param key 缓存键
* @param value 缓存值
*/
public void putCache(String cacheName,String key,Object value){
Cache cache = cacheManager.getCache(cacheName);
if(cache==null){
cacheManager.addCache(cacheName);
cache = cacheManager.getCache(cacheName);
}
cache.put(new Element(key, value));
System.out.println( cacheName + "已缓存");
}
/**
* 删除缓存
*
* @param cacheName 缓存策略
* @param key 键
*/
public void removeCache(String cacheName,String key){
Cache cache = cacheManager.getCache(cacheName);
if(cache!=null){
cache.remove(key);
}else{
System.out.println("cache is null...");
}
}
/**
* 替换缓存
*
* @param cacheName 缓存策略
* @param key 键
* @param value 值
*/
public void replaceCache(String cacheName,String key,String value){
Cache cache = cacheManager.getCache(cacheName);
if(cache!=null){
cache.replace(new Element(key,value));
}
}
/**
* 关闭缓存
*/
public void shutDownCache(){
cacheManager.shutdown();
}
public CacheManager getCacheManager() {
return cacheManager;
}
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
}
4、EhCache工具类测试
import com.hssmart.config.ehcache.EhcacheUtils;
import net.sf.ehcache.Cache;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 缓存测试controller
* @ClassName EhcacheController
* @Author syh
* @Date 2022/11/16 11:29
*/
@RestController
@RequestMapping(value = "/EhcacheController")
public class EhcacheController {
@Resource
private EhcacheUtils cacheUtils;
@GetMapping("/test")
public String test() {
try {
// 在HelloWorldCach1e策略下设置缓存
cacheUtils.putCache("HelloWorldCach1e", "kexq", "this is myCache test ...");
String s = (String)cacheUtils.getCache("HelloWorldCach1e","kexq");
System.out.println(s);
// 获取HelloWorldCach1e策略对象
Cache cache = cacheUtils.getEhcache("HelloWorldCach1e");
System.out.println(cache.getMemoryStoreEvictionPolicy().getName());;
System.out.println(cache);
}catch (Exception e){
e.printStackTrace();
}
return "index";
}
}