问题描述

在cache系统中writeThrough和writeBehind是两个常用的模式。
writeThrough是指,当用户更新缓存时,自动将值写入到数据源。
writeBehind是指,在用户更新缓存后异步更新到数据源。

ehcache实现

ehcache内部有一个CacheWriter接口,这个接口实现了cache一系列生命周期的钩子函数。
只需要实现自定义的写贯穿方法就可以在更新缓存时将对象写入底层的数据源

    //自定义的CacheWriter
    public class MyCacheWriter implements CacheWriter {
        public void write(Element element) throws CacheException {
            System.out.println("write->"+element.getObjectValue());    //write到数据层
        }
        public void writeAll(Collection elements) throws CacheException {
            System.out.println("writeall");           //write到数据层
        }
        ...
    }
    //cacheWriter的工厂方法
    public class MyCacheWriterFactory extends CacheWriterFactory{
        @Override
        public CacheWriter createCacheWriter(Ehcache cache, Properties properties) {
            return new MyCacheWriter();    //返回自定义的CacheWriter
        }

再将writer(的工厂方法)配置到cache中

    <cache name="writerCache" maxEntriesLocalHeap="10">
        <cacheWriter writeMode="write-through" maxWriteDelay="8"
            rateLimitPerSecond="5" writeCoalescing="true" writeBatching="true"
            writeBatchSize="20" retryAttempts="2" retryAttemptDelaySeconds="2">
            <cacheWriterFactory class="echach2.MyCacheWriterFactory"
                properties="test=1;" propertySeparator=";" />
        </cacheWriter>
    </cache>

可以看到CacheWrite关于write有两个方法,write和writeall,这是通过配置中的writeMode控制的当配置为write-through时会在每一次更新缓存时同步调用write方法。而如果设置为write-behind时则会根据maxWriteDelay调用writeall来讲这段时间的数据调用writeall。

ehcahce的自动load机制

常规的cache使用方法是

    if(cache.exist("key")){
        return cache.get("exist");
    }else{
        value=dao.get("key");
        cache.put("key",value);
        return value;
    }

是在检测cache没有命中时从dao获得数据再跟新到缓存。
有以下两种办法可以减少这种复杂的编码

SelfPopulatingCache

在ehcache中有一套SelfPopulatingCache机制,它可以在缓存miss的情况下load底层数据

    //cache load工厂
    public class MyCacheEntryFactory implements CacheEntryFactory {
        public Object createEntry(Object key) throws Exception {
            return new String("autoload "+key);    //自定义load方法
        }
    }
    //cache的装饰者工厂类
    public class MyCacheDecoratorFactory extends CacheDecoratorFactory{
        @Override
        public Ehcache createDecoratedEhcache(Ehcache cache, Properties properties) {
            return new SelfPopulatingCache(cache, new MyCacheEntryFactory());//使用SelfPopulatingCache并注册MyCacheEntryFactory 
        }

并在cache配置文件cache层中配置

    <cacheDecoratorFactory class="echach2.MyCacheDecoratorFactory"/>

这样获得的cache就会是经过装饰工厂生成的cache了
SelfPopulatingCache继承了BlockingCache,使用读写锁进行多线程更新和读取cache内容。
下面展示一下调用的代码

    @Test
    public void readWriteThroughCache() throws InterruptedException {
        CacheManager cache = CacheManager.create("cache.xml");
        Ehcache readWriteCache = cache.addCacheIfAbsent("writerCache");
        System.out.println("unexist key->"+readWriteCache.get(2).getObjectValue());    //自动读取值
        readWriteCache.putWithWriter(new Element(1, "value"));                         //写贯穿a需调用putWithWriter
        cache.shutdown();
    }

输出为

    unexist key->autoload 2
    write->value

使用getWithLoader

cache类拥有getWithLoader方法,它可以调用传入的loader对象进行数据load。但需要将get都改成这个方,而且对多线程同时写数据没有进行阻塞。

小结

以上介绍了ehcahe中write-thtough,write-behind与load-read的实现,可以在使用中适当选择数据加载及写入方式