EHCache学习笔记

jopen 9年前

介绍:

EHCache 是一个快速的、轻量级的、易于使用的、进程内的缓存。它支持 read-only 和 read/write 缓存,内存和磁盘缓存。是一个非常轻量级的缓存实现,而且从 1.2 之后就支持了集群。

配置:

    EHCache的配置非常灵活,可以在声明里配置,也可以在xml、程序中、构造函数中配置。下面在程序中动态的改变Cache的配置,如下:

Cache cache = manager.getCache("sampleCache");
CacheConfiguration config = cache.getCacheConfiguration();
config.setTimeToIdleSeconds(60);
config.setTimeToLiveSeconds(120);
config.setmaxEntriesLocalHeap(10000);
config.setmaxEntriesLocalDisk(1000000);

当然也可以冻结动态的Cache的配置,如下:

Cache cache = manager.getCache("sampleCache");
cache.disableDynamicFeatures();

在xml中将 <ehcache> 元素的属性 dynamicConfigattribute 改为 "false"即可。

 

多层次Cache的Cache Warming

要在缓存启动的时候同步缓存数据。EHCache2.5以上版本提供了支持,如下:

Replicated caches provide a boot strap mechanism which populates them. For example following is the JGroups bootstrap cache loader:

<bootstrapCacheLoaderFactory

class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory"

properties="bootstrapAsynchronously=true"/>

There are two new bootstrapCacheLoaderFactory implementations: one for standalone caches with DiskStores, and one for Terracotta Distributed caches.

 

DiskStoreBootstrapCacheLoaderFactory

The DiskStoreBootstrapCacheLoaderFactory loads elements from the DiskStore to the On-Heap Store and the Off-Heap store until either:

<bootstrapCacheLoaderFactory

class="net.sf.ehcache.store.DiskStoreBootstrapCacheLoaderFactory"

properties="bootstrapAsynchronously=true"/>

 

TerracottaBootstrapCacheLoaderFactory

The TerracottaBootstrapCacheLoaderFactory loads elements from the Terracotta L2 to the L1 based on what it was using the last time it ran. If this is the first time it has been run it has no effect.

<bootstrapCacheLoaderFactory class="net.sf.ehcache.terracotta.TerracottaBootstrapCacheLoaderFactory"

properties="bootstrapAsynchronously=true,

directory=dumps,

interval=5,

immediateShutdown=false,

snapshotOnShutDown=true,

doKeySnapshot=false,

useDedicatedThread=false"/>

当然EHCache的cache也可以配置读拷贝与写拷贝,详细见:copyOnRead and copyOnWrite cache configuration 。

 

ehcache.xml的配置

EHCache 默认到classpath下去找ehcache.xml,如果找不到,则找ehcache-failsafe.xml配置文件,而ehcache- failsafe.xml是打包在的ehcache的jar包中,所以它始终可以被找到。ehcache-failsafe.xml提供了一个非常简单的默认配置,它允许用户在配置chcache.xml之前就可以启动ehcache,其中的配置如下:

<ehcache>

<diskStore path="java.io.tmpdir"/>

<defaultCache

maxEntriesLocalHeap="10000"

eternal="false"

timeToIdleSeconds="120"

timeToLiveSeconds="120"

overflowToDisk="true"

maxEntriesLocalDisk="10000000"

diskPersistent="false"

diskExpiryThreadIntervalSeconds="120"

memoryStoreEvictionPolicy="LRU"

/>

</ehcache>

 

BigMemory的介绍与配置

    BigMemory是一个纯的java产品,它支持caches使用额外的内存空间来存储堆对象,它以快照式的任务存储(或称off-heap store,离线堆存储),打包在Enterprise Ehcache中,This off-heap store, which is not subject to Java GC, is 100 times faster than the DiskStore and allows very large caches to be created (we have tested this with over 350GB).

 

配置(Configuring caches to overflow to off-heap.)

 

Declarative Configuration-说明性的配置(通过xml配置文件)

<ehcache updateCheck="false" monitoring="off" dynamicConfig="false">

<defaultCache maxEntriesLocalHeap="10000"

eternal="true"

memoryStoreEvictionPolicy="LRU"

statistics="false" />

 

<cache name="sample-offheap-cache"

maxEntriesLocalHeap="10000"

eternal="true"

memoryStoreEvictionPolicy="LRU"

overflowToOffHeap="true"

maxMemoryOffHeap="1G"/>

</ehcache>

 

注意,NOTE: Dynamically Adding Caches With Fixed-Sized Offheap

If a CacheManager has a pooled offheap setting, caches with fixed-size offheap settings cannot be added dynamically. Dynamic in this case refers to caches that are added programmatically or using the Terracotta Developer Console while the CacheManager is running. A fixed-size offheap setting refers to a setting that specifies a size in bytes.

 

Programmatic Configuration(程序中配置)

public Cache createOffHeapCache()
{
  CacheConfiguration config = new CacheConfiguration("sample-offheap-cache", 10000)
  .overflowToOffHeap(true).maxMemoryOffHeap("1G");
  Cache cache = new Cache(config);
  manager.addCache(cache);
  return cache;
}

 

sizing caches

Tuning Ehcache often involves sizing cached data appropriately. Ehcache provides a number of ways to size the different data tiers using simple cache-configuration sizing attributes. These sizing attributes affect local memory and disk resources, allowing them to be set differently on each node.(翻译:调谐Ehcache常常涉及sizing cached 数据的合适性。Ehcache提供了大量的方式配置不同的数据层的大小,使用简单的cache-configuration sizing 属性。这些 sizing 属性会影响本地内存和磁盘资源,对于每个节点允许它们设置不同。)

 

使用ehcache

向cache取值与设值

示例1:

public class MyDataAccessClass
{
  private final Ehcache cache;
  public MyDataAccessClass(Ehcache cache)
  {
    this.cache = cache;
  }

  / read some data, check cache first, otherwise read from sor /
  public V readSomeData(K key)
  {
     Element element;
     if ((element = cache.get(key)) != null) {
         return element.getValue();
     }
      // note here you should decide whether your cache
     // will cache 'nulls' or not
     if (value = readDataFromDataStore(key)) != null) {
         cache.put(new Element(key, value));
     }
     return value;
  }
  / write some data, write to sor, then update cache /
  public void writeSomeData(K key, V value)
  {
     writeDataToDataStore(key, value);
     cache.put(new Element(key, value);
  }

 

    示例2:

public class MyDataAccessClass

{

private final Ehcache cache;

public MyDataAccessClass(Ehcache cache)

{

cache.registerCacheWriter(new MyCacheWriter());

this.cache = new SelfPopulatingCache(cache);

}

/ read some data - notice the cache is treated as an SOR.

the application code simply assumes the key will always be available

/

public V readSomeData(K key)

{

return cache.get(key);

}

/
write some data - notice the cache is treated as an SOR, it is

the cache's responsibility to write the data to the SOR.

/

public void writeSomeData(K key, V value)

{

cache.put(new Element(key, value);

}

/

Implement the CacheEntryFactory that allows the cache to provide

the read-through strategy

*/

private class MyCacheEntryFactory implements CacheEntryFactory

{

public Object createEntry(Object key) throws Exception

{

return readDataFromDataStore(key);

}

}

/


Implement the CacheWriter interface which allows the cache to provide

the write-through or write-behind strategy.

/

private class MyCacheWriter implements CacheWriter

public CacheWriter clone(Ehcache cache) throws CloneNotSupportedException;

{

throw new CloneNotSupportedException();

}

public void init() { }

void dispose() throws CacheException { }

void write(Element element) throws CacheException;

{

writeDataToDataStore(element.getKey(), element.getValue());

}

void writeAll(Collection elements) throws CacheException

{

for (Element element : elements) {

write(element);

}

}

void delete(CacheEntry entry) throws CacheException

{

deleteDataFromDataStore(element.getKey());

}

void deleteAll(Collection entries) throws CacheException

{

for (Element element : elements) {

delete(element);

}

}

}

}

 

示例3:

EHCacheUtils.java

package com.ttpod.common.tool.cache;

 

/**

@classDescription:ehcache工具类

/

 

public class EHCacheUtil {

    private static CacheManager cacheManager = null;

    private static Cache cache=null;

//------------------简化---------------------

    /**

    
初始化缓存管理容器

     /

    public static CacheManager initCacheManager() {

        try {

            if (cacheManager == null)

                cacheManager = CacheManager.getInstance();

            

        } catch (Exception e) {

            e.printStackTrace();

        }

        return cacheManager;

    }

 

    /**

    
初始化缓存管理容器

     @param path ehcache.xml存放的路徑

    
/

    public static CacheManager initCacheManager(String path) {

        try {

            

            if (cacheManager == null){

                System.out.println("为进来"+path);

                cacheManager = CacheManager.getInstance().create(path);

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

        return cacheManager;

    }

    

    /

     初始化cache

    
/

    public static Cache initCache(String cacheName) {

        checkCacheManager();

        

        if(null==cacheManager.getCache(cacheName)){

            cacheManager.addCache(cacheName);

        }

        cache=cacheManager.getCache(cacheName);

        return cache;

    }

    

    /


     添加缓存

    
@param key 关键字

     @param value 值

    
/

    public static void put(Object key,Object value) {

        checkCache();

        // 创建Element,然后放入Cache对象中

        Element element = new Element(key, value);

        cache.put(element);

    }

    /

     获取cache

    
@param key 关键字

     @return

    
/

    public static Object get(Object key){

        checkCache();

        Element element = cache.get(key);

        if(null==element){

            return null;

        }

        return element.getObjectValue();

    }

    //--------------更加方便使用的----------------

    //private static CacheManager myManager=null;

    //private static Cache myCache=null;

    

    /


     初始化缓存

    
@param cacheName 缓存名称

     @param maxElementsInMemory 元素最大数量

    
@param overflowToDisk 是否持久化到硬盘

     @param eternal 是否会死亡

    
@param timeToLiveSeconds 缓存存活时间

     @param timeToIdleSeconds 缓存的间隔时间

    
@return缓存

     @throws Exception 异常

    
/

    public static Cache initCache(String cacheName,int maxElementsInMemory,

            boolean overflowToDisk,boolean eternal,long timeToLiveSeconds,

            long timeToIdleSeconds) throws Exception{

        try {

            CacheManager singletonManager = CacheManager.create();

            Cache myCache = singletonManager.getCache(cacheName);

            if(myCache!=null){

                CacheConfiguration config = cache.getCacheConfiguration();

                config.setTimeToLiveSeconds(timeToLiveSeconds);

                config.setMaxElementsInMemory(maxElementsInMemory);

                config.setOverflowToDisk(overflowToDisk);

                config.setEternal(eternal);

                config.setTimeToLiveSeconds(timeToLiveSeconds);

                config.setTimeToIdleSeconds(timeToIdleSeconds);

            }

            if(myCache==null){

                Cache memoryOnlyCache = new Cache(cacheName, maxElementsInMemory, overflowToDisk,

                        eternal, timeToLiveSeconds, timeToIdleSeconds);

                singletonManager.addCache(memoryOnlyCache);

                myCache = singletonManager.getCache(cacheName);

            }

            return myCache;

        } catch (Exception e) {

            e.printStackTrace();

            throw new Exception("init cache "+cacheName+" failed!!!");

        }

    }

    

    /

     初始化cache

    
@param cacheName cache的名字

     @param timeToLiveSeconds 有效时间

    
@return cache 缓存

     @throws Exception 异常

    
/

    public static Cache initCache(String cacheName,long timeToLiveSeconds) throws Exception{

        try {

            CacheManager myManager = CacheManager.create();

            Cache myCache = myManager.getCache(cacheName);

            if(myCache!=null){

                CacheConfiguration config = myCache.getCacheConfiguration();

                config.setTimeToLiveSeconds(timeToLiveSeconds);

                config.setMaxElementsInMemory(EHCacheConfig.MAXELEMENTSINMEMORY);

                config.setMemoryStoreEvictionPolicy(EHCacheConfig.MEMORYSTOREEVICTIONPOLICY);

                config.setOverflowToDisk(EHCacheConfig.OVERFLOWTODISK);

                config.setEternal(EHCacheConfig.ETERNAL);

                config.setTimeToLiveSeconds(timeToLiveSeconds);

                config.setTimeToIdleSeconds(EHCacheConfig.TIMETOIDLESECONDS);

                config.setDiskPersistent(EHCacheConfig.DISKPERSISTENT);

                config.setDiskExpiryThreadIntervalSeconds(0);

            }

            if(myManager.getCache(cacheName)==null){

                myCache = new Cache(

                 new CacheConfiguration(cacheName, EHCacheConfig.MAXELEMENTSINMEMORY)

                 .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)

                 .overflowToDisk(EHCacheConfig.OVERFLOWTODISK)

                 .eternal(EHCacheConfig.ETERNAL)

                 .timeToLiveSeconds(timeToLiveSeconds)

                 .timeToIdleSeconds(EHCacheConfig.TIMETOIDLESECONDS)

                 .diskPersistent(EHCacheConfig.DISKPERSISTENT)

                 .diskExpiryThreadIntervalSeconds(0));

                myManager.addCache(myCache);

            }

            return myCache;

        } catch (Exception e) {

            e.printStackTrace();

            throw new Exception("init cache "+cacheName+" failed!!!");

        }

    }

    

    /


     修改缓存

    
@param cacheName 缓存名

     @param timeToLiveSeconds 有效时间

    
@param maxElementsInMemory 最大数量

     @return真

    
@throws Exception 异常

     /

    public static boolean modifyCache(String cacheName,

            long timeToLiveSeconds,int maxElementsInMemory) throws Exception{

        try {

            if(StringUtils.isNotBlank(cacheName) && timeToLiveSeconds!=0L

                    && maxElementsInMemory!=0){

                CacheManager myManager = CacheManager.create();

                Cache myCache = myManager.getCache(cacheName);

                CacheConfiguration config = myCache.getCacheConfiguration();

                config.setTimeToLiveSeconds(timeToLiveSeconds);

                config.setMaxElementsInMemory(maxElementsInMemory);

                return true;

            }else{

                return false;

            }

        } catch (Exception e) {

            e.printStackTrace();

            throw new Exception("modify cache "+cacheName+" failed!!!");

        }

    }

    

    /**

    
请求向ehcache中设置值

     @param vesselName 容器名

    
@param key 键

     @param value 值

    
@return返回真

     @throws Exception 异常

    
/

    public static boolean setValue(String cacheName,String key, Object value) throws Exception{

        try {

            EHCacheUtil.initCacheManager();

            EHCacheUtil.initCache(cacheName);

            EHCacheUtil.put(key, value);

            //cacheManager.

            return true;

        } catch (Exception e) {

            e.printStackTrace();

            throw new Exception("set cache "+cacheName+" failed!!!");

        }

    }

    

    /

     从ehcache的指定容器中取值

    
@param key 键

     @return返回Object类型的值

    
@throws Exception 异常

     */

    public static Object getValue(String cacheName,String key) throws Exception{

        try {

            EHCacheUtil.initCacheManager();

            EHCacheUtil.initCache(cacheName);

            return EHCacheUtil.get(key);

        } catch (Exception e) {

            e.printStackTrace();

            throw new Exception("get cache "+cacheName+" failed!!!");

        }

    }

    

    /


     删除指定的ehcache容器

    
@param vesselName

     @return真

    
@throws Exception 异常

     /

    public static boolean removeEhcache(String cacheName) throws Exception{

        try {

            initCacheManager();

            initCache(cacheName);

            removeCache(cacheName);

            return true;

        } catch (Exception e) {

            e.printStackTrace();

            throw new Exception("remove cache "+cacheName+" failed!!!");

        }

    }

    //------------------方便调用------------

    /**

    
释放CacheManage

    

    
/

    public static void shutdown() {

        cacheManager.shutdown();

    }

    

    /

     移除cache

    
@param cacheName

     */

    public static void removeCache(String cacheName){

        checkCacheManager();

        cache=cacheManager.getCache(cacheName);

        if(null!=cache){

            cacheManager.removeCache(cacheName);

        }

        

    }

    /


     移除cache中的key

    
@param cacheName

     /

    public static void remove(String key){

        checkCache();

        cache.remove(key);

 

    }

    

    /**

    
移除所有cache

     /

    public static void removeAllCache(){

        checkCacheManager();

        cacheManager.removalAll();

    }

    

    /**

    
移除所有Element

     /

    public static void removeAllKey(){

        checkCache();

        cache.removeAll();

    }

    

    /**

    
获取所有的cache名称

     @return

    
/

    public static String[]getAllCaches(){

        checkCacheManager();

        return cacheManager.getCacheNames();

    }

    /

     获取Cache所有的Keys

    
@return

     */

    public static List getKeys(){

        checkCache();

        return cache.getKeys();

    }

 

    /


     检测cacheManager

    
/

    private static void checkCacheManager(){

        if(null==cacheManager){

            throw new IllegalArgumentException("调用前请先初始化CacheManager值:EHCacheUtil.initCacheManager");

        }

        

    }

    

    private static void checkCache(){

        if(null==cache){

            throw new IllegalArgumentException("调用前请先初始化Cache值:EHCacheUtil.initCache(参数)");

        }

    }

    

    public static void main(String[]arg){

        //初始化--必须

        EHCacheUtil.initCacheManager();

        String[]caches=EHCacheUtil.getAllCaches();

        for(String cache:caches){

            System.out.println(cache);

        }

//        //放入Test Cache中

//        EHCacheUtil.initCache("ceshi");

//        EHCacheUtil.put("F", "hello world");

//        //--1111

//        System.out.println(EHCacheUtil.get("F"));

//    

//        

//        EHCacheUtil.initCacheManager();

//        EHCacheUtil.initCache("Test");

//        EHCacheUtil.put("F", "hello world1");

//        

//        //----2222

//        System.out.println(EHCacheUtil.get("F"));

//        

//        //初始化--必须

//        EHCacheUtil.initCacheManager();

//        //放入Test Cache中

//        EHCacheUtil.initCache("ceshi");

//        //----3333

//        System.out.println(EHCacheUtil.get("F"));

//        

//        

//        //初始化--必须

//        EHCacheUtil.initCacheManager();

//        //放入Test Cache中

//        EHCacheUtil.initCache("cassger");

//        //----

//        EHCacheUtil.put("F", "fangs");

//        System.out.println(EHCacheUtil.get("F"));

        

    }

}

 

EHCacheConfig.java

package com.ttpod.common.tool.cache;

/

@className:EHCacheConfig.java

@classDescription:

*/

public class EHCacheConfig {

    /


     元素最大数量

    
/

    public static int MAXELEMENTSINMEMORY=50000;

    /

     是否把溢出数据持久化到硬盘

    
/

    public static boolean OVERFLOWTODISK=true;

    /


     是否会死亡

    
/

    public static boolean ETERNAL=false;

    /

     缓存的间隔是时间

    
/

    public static int TIMETOIDLESECONDS=300;

    /


     需要持久化到硬盘否

    
/

    public static boolean DISKPERSISTENT=false;

    /*

    
内存存取策略

     */

    public static String MEMORYSTOREEVICTIONPOLICY="LFU";

 

}

 

hibernate中的二级缓存

命名缓存查询

In addition, a QueryCache can be given a specific name in Hibernate using Query.setCacheRegion(String name). The name of the cache in ehcache.xml is then the name given in that method. The name can be whatever you want, but by convention you should use "query." followed by a descriptive name. E.g.

<cache name="query.AdministrativeAreasPerCountry"

maxEntriesLocalHeap="5"

eternal="false"

timeToLiveSeconds="86400"

overflowToDisk="true"/>

 

使用缓存查询

For example, let's say we have a common query running against the Country Domain. Code to use a query cache follows:

public List getStreetTypes(final Country country) throws HibernateException {

final Session session = createSession();

try {

final Query query = session.createQuery(

"select st.id, st.name"

+ " from StreetType st "

+ " where st.country.id = :countryId "

+ " order by st.sortOrder desc, st.name");

query.setLong("countryId", country.getId().longValue());

query.setCacheable(true);

query.setCacheRegion("query.StreetTypes");

return query.list();

} finally {

session.close();

}

}

The query.setCacheable(true) line caches the query.Thequery.setCacheRegion("query.StreetTypes") line sets the name of the Query Cache. Alex Miller has a good article on the query cache here.

 

程序中配置ehcache

 

 

Differences Between Distributed Cache and Standalone or Replicated Cache

CacheManagers can be configured programmatically with a fluent API. The example below creates a CacheManager with a Terracotta configuration specified in an URL, and creates a defaultCache and a cache named "example".

Configuration configuration = new Configuration()
.terracotta(new TerracottaClientConfiguration().url("localhost:9510"))
.defaultCache(new CacheConfiguration("defaultCache", 100))
.cache(new CacheConfiguration("example", 100)
.timeToIdleSeconds(5)
.timeToLiveSeconds(120)
.terracotta(new TerracottaConfiguration()));
CacheManager manager = new CacheManager(configuration);

The above example looks for sampleTerracottaCache. In ehcache.xml, we need to uncomment or add the following line:

<terracottaConfig url="localhost:9510"/>

This tells Ehcache to load the Terracotta server config from localhost port 9510. For url configuration options, refer to "Adding an URL Attribute" in Terracotta Clustering Configuration Elements. Note: You must have a Terracotta 3.1.1 or higher server running locally for this example.

Next we want to enable Terracotta clustering for the cache named sampleTerracottaCache. Uncomment or add the following in ehcache.xml.

<cache name="sampleTerracottaCache"

maxEntriesLocalHeap="1000"

eternal="false"

timeToIdleSeconds="3600"

timeToLiveSeconds="1800"

overflowToDisk="false">

<terracotta/>

</cache>

That's it!