Ehcache3.4 数据的持久化操作

本文介绍了Ehcache的两种持久化方式:非配置文件和配置文件方式,并提供了详细的代码示例,包括如何将数据持久化到磁盘、读取数据及清空持久化信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要进行数据持久化操作

  我们知道,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端口号被占用的异常。");
        }
    }

}

源码:ehcache-demo2


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值