为什么要进行数据持久化操作
我们知道,Ehcache中的数据是以键值对的形式存储在内存中的,由于内存比硬盘读写速度快很多,因而存放在内存中的信息其读取速度是很快的。但是它的缺点也很明显,那就是一旦程序退出,那么内存中的信息也就随之丢失,为了解决这一问题,因而我们要对其进行相应的持久化操作。
为了进行持久化操作,我去官网上查看官方文档,无奈官方文档中没有相应的详细信息,而是一带而过,挖了一个大坑;而百度与谷歌的结果,得到的往往是过时的信息,因而也没有太大的参考价值。所以说因为这种事情我还折腾了半天,不过我发现最有参考价值的地方还是api文档,如下:
Ehcache数据持久化
Ehcache的数据持久化操作一共有两种方式,其一是采用非配置文件的方式;其二是采用配置文件的方式。
非配置文件持久化
由于注释中已经写得很详细了,所以说我这里就简单的说一下,该程序所实现的持久化操作是将持久化数据存放到项目的target路径中,而该路径的获取有多种方式,其中this.getClass().getResource("/").getPath()
等价于EhcacheAction2.class.getResource("/").getPath()
,我们可以通过这种方式获取文件的相对输出路径,但是这需要指出的是,这里是用来进行测试的,所以说才会输出到target路径中,在实际开发时,是不应该输出到该路径下的。
@Test
public void test2(){
String path = this.getClass().getResource("/").getPath();
log.info("----" + path );
//对于磁盘层,数据存储在磁盘上。磁盘的速度越快、越专注,访问数据的速度就越快。
//要获得一个PersistentCacheManager,其实就是一个普通的通常的CacheManager,但是具有销毁缓存的能力。
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
//EhcacheAction2.class.getResource("/").getPath()
//F:\Test2\ehcache-parent\ehcache-demo2\target\classes\myData
//System.getProperty("user.dir")
//F:\Test2\ehcache-parent
//提供一个存储数据的位置。
.with(CacheManagerBuilder.persistence(new File(path, "myData")))
.withCache("threeTieredCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
//为缓存使用的磁盘定义一个资源池。第三个参数是一个布尔值,用于设置磁盘池是否持久。
// 当设置为true时,池是持久的。当使用两个参数磁盘(long、MemoryUnit)的版本时,池就不会持久。
ResourcePoolsBuilder.newResourcePoolsBuilder()
//您为堆定义了一个资源池,该堆内只允许存放10个条目
.heap(10, EntryUnit.ENTRIES)
//您为非堆定义了一个资源池。仍然非常快,而且有点大。该大小为1M
/*.offheap(1, MemoryUnit.MB)*/
//您为磁盘定义一个持久的资源池。它是持久性的,因为它应该是(最后一个参数是正确的)。
.disk(10, MemoryUnit.MB, true))
)
.build(true);
Cache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class, String.class);
//存储在缓存中的所有值都将在JVM重新启动后可用(假定CacheManager通过调用close()已被干净地关闭了。
threeTieredCache.put(1L, "stillAvailableAfterRestart");
log.info("threeTieredCache,获取信息:{}",threeTieredCache.get(1L));
persistentCacheManager.close();
//上面的示例分配了非常少量的磁盘存储。您通常会使用更大的存储空间。
//持久性意味着缓存将在JVM重新启动后存活。在重新启动JVM并在相同的位置创建一个CacheManager磁盘持久性之后,缓存中的所有内容仍然存在。
//磁盘层不能在缓存管理器之间共享。一个持久性目录是专门针对一个缓存管理器的。
//请记住,存储在磁盘上的数据必须被序列化/反序列化,并写入/从磁盘读取/读取,因此比堆和off堆要慢。因此,磁盘存储很有趣:
//* 你有大量的数据不适合堆在堆里
//* 你的磁盘比它缓存的存储快得多
//* 你对持久性感兴趣
}
配置文件持久化
添加ehcache.xml配置文件
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
<!--ehcache的持久化操作保存地址-->
<!--<disk-store thread-pool=""></disk-store> 这个不能使用,用了只会报错 -->
<persistence directory="F:/Test2/ehcache-parent/ehcache-demo2/myData"/>
<!-- 1、声明一个名为foo的Cache-->
<cache alias="threeTieredCache">
<!--2、foo的键值对被声明为字符串类型,如果没有指明,默认是Object类型。-->
<key-type>java.lang.Long</key-type>
<value-type>java.lang.String</value-type>
<resources>
<!--3、foo被声明在堆上保存多达10个条目。-->
<heap unit="entries">10</heap>
<!--<offheap unit="MB">1</offheap>-->
<!--4、硬盘存储空间为10M-->
<disk unit="MB" persistent="true">10</disk>
</resources>
</cache>
</config>
添加测试代码
在这里,我一共展示了三个测试方法,分别是在test()中持久化100条数据,在testCount()中打印出持久化的数据并统计信息的条数,在testClean()中,我们可以清空持久化的数据。
这里需要注意的是org.ehcache.Cache中,由于其采用的是链表式数据结构,因而其并没有提供统计信息条数的方法,这一点给人的感觉是很不友好,如果要想获取统计的信息总条数,那么我们还得一条一条的遍历信息,然后数出信息的总条数来。
由于org.ehcache.Cache继承自Iterable
package com.lyc.ehcache;
import lombok.extern.slf4j.Slf4j;
import org.ehcache.*;
import org.ehcache.config.Configuration;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.xml.XmlConfiguration;
import org.junit.Assert;
import org.junit.Test;
import java.net.URL;
import java.util.Iterator;
@Slf4j
public class Ehcache2Test {
/**
* 将Ehcache中的数据持久化
*/
@Test
public void test(){
//1、获取到XML文件位置的URL
URL myUrl = getClass().getResource("/ehcache.xml");
//2、实例化一个XmlConfiguration,将XML文件URL传递给它
Configuration xmlConfig = new XmlConfiguration(myUrl);
//3、使用静态的org.ehcache.config.builders.CacheManagerBuilder.newCacheManager(org.ehcache.config.Configuration)
//使用XmlConfiguration的Configuration创建你的CacheManager实例。
CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
try {
cacheManager.init();
Cache<Long, String> threeTieredCache = cacheManager.getCache("threeTieredCache",Long.class, String.class);
//循环遍历插入100条数据
for (long i = 0;i < 100;i ++){
threeTieredCache.put(i, "这是第:" + i + "条信息");
}
//等待10秒钟(主要是方便信息写入硬盘)
Thread.sleep(10000);
//循环遍历输出
threeTieredCache.forEach( cc -> {
log.info("threeTieredCache,主键:{},值:{}",cc.getKey(),cc.getValue());
});
cacheManager.close();
} catch (StateTransitionException se){
//异常之后就打印堆栈信息
se.printStackTrace();
log.info("很抱歉,运行失败!");
cacheManager.close();
log.info("关闭cacheManager,否则下次启用的时候会报jvm端口号被占用的异常。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 从硬盘读取数据
*/
@Test
public void testCount(){
int count = 0;
//1、获取到XML文件位置的URL
URL myUrl = getClass().getResource("/ehcache.xml");
//2、实例化一个XmlConfiguration,将XML文件URL传递给它
Configuration xmlConfig = new XmlConfiguration(myUrl);
//3、使用静态的org.ehcache.config.builders.CacheManagerBuilder.newCacheManager(org.ehcache.config.Configuration)
//使用XmlConfiguration的Configuration创建你的CacheManager实例。
CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
try {
cacheManager.init();
Cache<Long, String> threeTieredCache = cacheManager.getCache("threeTieredCache",Long.class, String.class);
Iterator<Cache.Entry<Long,String>> iterator = threeTieredCache.iterator();
while(iterator.hasNext()){
++ count;
Cache.Entry<Long,String> entry = iterator.next();
log.info("threeTieredCache,主键:{},值:{}",entry.getKey(),entry.getValue());
}
log.info("信息的总条数为:{}",count);
//断言输出的信息结果条数,如果是100条,则验证正确。
Assert.assertEquals(100,count);
cacheManager.close();
} catch (StateTransitionException se){
//异常之后就打印堆栈信息
se.printStackTrace();
log.info("很抱歉,运行失败!");
cacheManager.close();
log.info("关闭cacheManager,否则下次启用的时候会报jvm端口号被占用的异常。");
}
}
/**
* 清空持久化的信息
*/
@Test
public void testClean(){
//1、获取到XML文件位置的URL
URL myUrl = getClass().getResource("/ehcache.xml");
//2、实例化一个XmlConfiguration,将XML文件URL传递给它
Configuration xmlConfig = new XmlConfiguration(myUrl);
//3、使用静态的org.ehcache.config.builders.CacheManagerBuilder.newCacheManager(org.ehcache.config.Configuration)
//使用XmlConfiguration的Configuration创建你的CacheManager实例。
CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
try {
cacheManager.init();
Cache<Long, String> threeTieredCache = cacheManager.getCache("threeTieredCache",Long.class, String.class);
//清空信息
threeTieredCache.clear();
//循环遍历输出
threeTieredCache.forEach( cc -> {
log.info("threeTieredCache,主键:{},值:{}",cc.getKey(),cc.getValue());
});
cacheManager.close();
} catch (StateTransitionException se){
//异常之后就打印堆栈信息
se.printStackTrace();
log.info("很抱歉,运行失败!");
cacheManager.close();
log.info("关闭cacheManager,否则下次启用的时候会报jvm端口号被占用的异常。");
}
}
}