Hibernate性能优化之EHCache缓存

像Hibernate这种ORM框架,相较于JDBC操做,须要有更复杂的机制来实现映射、对象状态管理等,所以在性能和效率上有必定的损耗。html

在保证避免映射产生低效的SQL操做外,缓存是提高Hibernate的关键之一。java

加入缓存能够避免数据库调用带来的链接建立与销毁、数据打包拆包、SQL执行、网络传输,良好的缓存机制和合理的缓存模式能带来性能的极大提高,EHCache就提供了这种良好的缓存机制。数据库

在考虑给系统加入缓存进行优化前,复用SessionFactory是Hibernate优化最优先、最基础的性能优化方法,参考上一篇《Hibernate性能优化之SessionFactory重用》。json

Hibernate的缓存机制缓存


缓存的级别通常分为三种,每一种缓存的范围更大:安全

事务级缓存:Hibernate中称为一级缓存,在一个Session中共享缓存对象;性能优化

应用级缓存:Hibernate中称为二级缓存,在一个SessionFactory中共享缓存对象,SessionFactory在整个应用范围内重用;网络

分布式缓存:部署为单独的实例,如Redis、Memcache等。多线程

Hibernate的按如下方式进行缓存:框架

当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;

查不到,若是配置了二级缓存,那么从二级缓存中查;

若是都查不到,再查询数据库,把结果按照ID放入到缓存删除、更新、增长数据的时候,同时更新缓存。

Hibernate默认不启用二级缓存,EHCache是Hibernate中的二级缓存插件,使用Hibernate的系统能够直接使用EHCache缓存。

为何要直接使用EHCache


回头来看那句话:良好的缓存机制和合理的缓存模式能带来性能的极大提高。

Hibernate的缓存模式是什么?

根据ID来缓存对象,也就是Session的get、load操做时。

这种缓存模式的弊端有两点:

一、应用场景太单一,系统中大量的列表式查询缓存起不到做用;

二、一些系统中经过ThreadLocal在线程中重用Session,每一个线程可能须要大量处理不用的业务逻辑,缓存命中率很低;若是不重用Session,通常的场景缓存命中率更低。

既然EHCache已经提供了良好的缓存机制,结合本身系统的业务来优化缓存模式才是最佳的。

如何使用EHCache


EHCache是Hibernate中的二级缓存插件,使用Hibernate的系统能够直接使用EHCache缓存,不须要再添加其余jar包。

新建EHCache配置文件,具体的配置含义能够查手册:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:noNamespaceSchemaLocation="ehcache.xsd">  
  <diskStore path="java.io.tmpdir"/>  
  <defaultCache  
    maxElementsInMemory="10000"  
    maxElementsOnDisk="0"  
    eternal="true"  
    overflowToDisk="true"  
    diskPersistent="false"  
    timeToIdleSeconds="0"  
    timeToLiveSeconds="0"  
    diskSpoolBufferSizeMB="50"  
    diskExpiryThreadIntervalSeconds="120"  
    memoryStoreEvictionPolicy="LFU"  
    />  
  <cache name="restCache"  
    maxElementsInMemory="100"  
    maxElementsOnDisk="0"  
    eternal="false"  
    overflowToDisk="false"  
    diskPersistent="false"  
    timeToIdleSeconds="119"  
    timeToLiveSeconds="119"  
    diskSpoolBufferSizeMB="50"  
    diskExpiryThreadIntervalSeconds="120"  
    memoryStoreEvictionPolicy="FIFO"  
    />  
</ehcache>  

EHCache的一个优势是线程安全的,适合多线程的使用场景,能简化开发人员的使用。

所以我写了一个单例模式,避免每次在方法里写getCache,这个类也涵盖了EHCache的基本使用:

public class EHCacheFactory {
    
    private final CacheManager manager;
    private final Cache cache;
    
    private EHCacheFactory() {
        manager = CacheManager.create(getClass().getResource("/ehcache.xml"));
        cache = manager.getCache("restCache");
    }
    
    public Element getCache(String strKey) {
        return EHCacheFactory.getInstance().getCache().get(strKey);
    }
    
    public void setCache(String strKey, String strVal) {
        EHCacheFactory.getInstance().getCache().put(new Element(strKey, strVal));
    }
    
    public Cache getCache() {
        return cache;
    }
    
    private static class SingletonHolder {

        private final static EHCacheFactory INSTANCE = new EHCacheFactory();
    }

    public static EHCacheFactory getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

个人系统是JAVA REST,在须要缓冲的REST接口中加入了EHCache缓存,经过URL参数做为缓存键值,REST接口返回的json数据做为缓存值,这种缓存模式很是适合REST。

使用ab进行了简单的性能测试:

在一个简答查询接口中,性能提高一倍;

在一个略复杂接口中,执行四、5个查询,加入缓存后性能提高20倍。

在这里就不贴ab测试结果了,你们能够自行测试一下。


记录,为更好的本身!

相关文章
相关标签/搜索