spring+hibernate整合ehcache

1.使用ehcache来提高系统的性能,现在用的非常多, 也支持分布式的缓存,在hibernate当中作为二级缓存的实现产品,可以提高查询性能。

2.在之前的struts2.12+Spring3.2+hibernate4.2集成系列的文章中已经集成了ehcachejar包了hibernate4.2当中可以找到ehcache-core-2.4.3.jar hibernate-ehcache-4.2.0.Final.jar

Hibernate 本身支持ehcahce的集成,提对他进行了集成的封装。

3. 在项目的src下面添加ehcache的配置文件ehcache.xml

 

Xml代码    收藏代码
  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">  
  2.     <!-- 
  3.     Subdirectories can be specified below the property e.g. java.io.tmpdir/one 
  4.     -->  
  5.     <diskStore path="java.io.tmpdir"/>  
  6.   
  7.     <!--  
  8.     Mandatory Default Cache configuration. These settings will be applied to caches  
  9.     created programmtically using CacheManager.add(String cacheName)  
  10.     -->  
  11.     <defaultCache  
  12.          maxElementsInMemory="10000"  
  13.          eternal="false"  
  14.          timeToIdleSeconds="120"  
  15.          timeToLiveSeconds="120"  
  16.          overflowToDisk="true"  
  17.          maxElementsOnDisk="10000000"  
  18.          diskPersistent="false"  
  19.          diskExpiryThreadIntervalSeconds="120"  
  20.          memoryStoreEvictionPolicy="LRU"  
  21.      />  
  22.       
  23.     <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"  
  24.            maxElementsInMemory="5000"   
  25.            eternal="true"   
  26.            overflowToDisk="true" />  
  27.     <cache name="org.hibernate.cache.internal.StandardQueryCache"  
  28.            maxElementsInMemory="10000"   
  29.            eternal="false"   
  30.            timeToLiveSeconds="120"  
  31.            overflowToDisk="true" />    
  32.       
  33.     <!--  
  34.     java文件注解查找cache方法名的策略:如果不指定java文件注解中的region="ehcache.xml中的name的属性值",   
  35.     则使用name名为com.lysoft.bean.user.User的cache(即类的全路径名称), 如果不存在与类名匹配的cache名称, 则用 defaultCache  
  36.     如果User包含set集合, 则需要另行指定其cache  
  37.     例如User包含citySet集合, 则也需要  
  38.     添加配置到ehcache.xml中  
  39.     -->      
  40.     <cache name="copierCache" maxElementsInMemory="2000" eternal="false"   
  41.            timeToIdleSeconds="120" timeToLiveSeconds="120"  
  42.            overflowToDisk="true" />    
  43.           
  44. </ehcache>  

4. 在spring 集成hibernate 的配置文件中,添加如下配置

 

Xml代码    收藏代码
  1. <!-- 开启查询缓存 -->  
  2. <prop key="hibernate.cache.use_query_cache">true</prop>  
  3. <!-- 开启二级缓存 -->  
  4. <prop key="hibernate.cache.use_second_level_cache">true</prop>  
  5. <!-- 高速缓存提供程序 -->   
  6. <!-- 由于spring也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->  
  7. <prop key="hibernate.cache.region.factory_class">  
  8.      org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory  
  9. </prop>  

5. Spring也使用ehcache, 所以也需要在spring配置文件中添加ehcache的配置

 

Xml代码    收藏代码
  1. <!-- cacheManager, 指定ehcache.xml的位置 -->   
  2.     <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">  
  3.         <property name="configLocation">  
  4.             <value>classpath:ehcache.xml</value>  
  5.         </property>  
  6.         <!-- 由于hibernate也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->  
  7.         <property name="shared" value="true"/>  
  8.     </bean>  

 

 由于hibernate spring都使用了ehcache, 可以由spring 或者hibernate 来管理ehcache

使用spring管理ehcache的好处是可以使用依赖注入,可以在程序中注入使用,比较方便,因此采用spring管理ehcache比较好, 不过spring hibernate一起使用ehcache的话,会产生两个CacheManager,这样在分布式缓存中会有数据部同步的问题, 需要配置一下,springhibernate公用一个CacheManager

 

EHCache升级到1.2之后,对原来CacheManager的实例化方式进行了一些修改。在之前的EHCache中,只会存在一个CacheManager的实例,所有使用EHCache组件的应用都共享这个实例。

而在EHCache 1.2之后,则提供了对多实例的支持。这样,在有多个功能模块同时使用EHCache的时候就要注意实例方式的选取了。

CacheManager是否为多实例取决于获得CacheManager的方法。如果使用构造方法来获得CacheManager对象的实例,那么就会获得一个新的CacheManager实例。而使用create()方法获得CacheManager实例的时候则会获得singleton的实例(如果还没有创建,它会自动地创建)。

现在,在一个应用中,默认情况下Hibernate会创建一个单独的CacheManager实例,如果在其他功能模块中也需要使用这个CahceManager实例,就需要使用EHCache所提供的singletonCacheProvider。在Hibernate配置文件中的配置方法如下:

在配置hibernate的相关信息里面设置成单实例的CacheManager Factory

 

Xml代码    收藏代码
  1. <!-- 由于spring也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->  
  2. <prop key="hibernate.cache.region.factory_class">  
  3.      org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory  
  4. </prop>  

 spring 配置ehcache里面需要添加这个属性 

 

Xml代码    收藏代码
  1. <!-- 由于hibernate也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->  
  2.         <property name="shared" value="true"/>  

  

Java代码    收藏代码
  1. 我们来看一下hibernate配置里面 SingletonEhCacheRegionFactory这个类的源代码,  
  2. String configurationResourceName = null;  
  3.             if ( properties != null ) {  
  4.                 configurationResourceName = (String) properties.get( NET_SF_EHCACHE_CONFIGURATION_RESOURCE_NAME );  
  5.             }  
  6.             if ( configurationResourceName == null || configurationResourceName.length() == 0 ) {  
  7.                 manager = CacheManager.create();  
  8.                 REFERENCE_COUNT.incrementAndGet();  
  9.             }  
  10.   
  11. 我们可以看到 会以默认的配置文件名称 创建一个CacheManager 对象,并且是以CacheManager.create()方法创建的, 说明只会产生一个CacheManager 实例。  
  12. 再来看一下spring EhCacheManagerFactoryBean这个类的源码  
  13. private boolean shared = false;  
  14. if (this.shared) {  
  15.                 this.cacheManager = (is != null ? CacheManager.create(is) : CacheManager.create());  
  16.             }  
  17.             else {  
  18.                 this.cacheManager = (is != null ? new CacheManager(is) : new CacheManager());  
  19.             }  
  20.   
  21. 发现里面有个share的变量, 是否是共享使用CacheManger, 如果是true, 调用的是CacheManager.create()的方法创建CacheManager,false调用 new CacheManager方法会生成多个实例。  
  22. 再看看CacheManger里面的create方法源码  
  23. private static volatile CacheManager singleton;  
  24. if (singleton != null) {  
  25.             return singleton;  
  26.         }  
  27.         synchronized (CacheManager.class) {  
  28.             if (singleton == null) {  
  29.                 LOG.debug("Creating new CacheManager with default config");  
  30.                 singleton = new CacheManager();  
  31.             } else {  
  32.                 LOG.debug("Attempting to create an existing singleton. Existing singleton returned.");  
  33.             }  
  34.             return singleton;  
  35.         }  
  36.   
  37. 可以看到CacheManager 定义的变量是static 的,create方面里面做了判断singleton 是否已经创建过。  
  38.   
  39.   
  40. 配置好后, 把项目部署到tomcat上面,以debug的方式启动, 可以debug到源码可以观察CacheManger 的创建过程。  
  41.   
  42. 来检验一下缓存是否起作用了,添加一个User类  
  43. package com.lysoft.bean.user;  
  44.   
  45. import java.io.Serializable;  
  46. import java.util.Date;  
  47.   
  48. import javax.persistence.Column;  
  49. import javax.persistence.Entity;  
  50. import javax.persistence.GeneratedValue;  
  51. import javax.persistence.Id;  
  52. import javax.persistence.Table;  
  53. import javax.persistence.Temporal;  
  54. import javax.persistence.TemporalType;  
  55.   
  56. import org.hibernate.annotations.Cache;  
  57. import org.hibernate.annotations.CacheConcurrencyStrategy;  
  58.   
  59. @Entity   
  60. @Table (name = "t_user")  
  61. @Cache (usage = CacheConcurrencyStrategy.READ_WRITE, region="longTimeCache")  
  62. public class User implements Serializable {  
  63.     private static final long serialVersionUID = 4239100106344646509L;  
  64.     private Integer id;  
  65.     private String userName;  
  66.     private String firstName;  
  67.     private Date createTime;  
  68.   
  69.     @Id @GeneratedValue  
  70.     public Integer getId() {  
  71.         return id;  
  72.     }  
  73.   
  74.     public void setId(Integer id) {  
  75.         this.id = id;  
  76.     }  
  77.   
  78.     @Column (length = 50, nullable = false)  
  79.     public String getUserName() {  
  80.         return userName;  
  81.     }  
  82.   
  83.     public void setUserName(String userName) {  
  84.         this.userName = userName;  
  85.     }  
  86.   
  87.     public String getFirstName() {  
  88.         return firstName;  
  89.     }  
  90.   
  91.     public void setFirstName(String firstName) {  
  92.         this.firstName = firstName;  
  93.     }  
  94.   
  95.     @Temporal(TemporalType.TIMESTAMP)  
  96.     public Date getCreateTime() {  
  97.         return createTime;  
  98.     }  
  99.   
  100.     public void setCreateTime(Date createTime) {  
  101.         this.createTime = createTime;  
  102.     }  
  103.   
  104. }  
  105.   
  106.   
  107. 添加了一个注解@Cache , 指定缓存策略是读和写, 并指定使用的缓存区域  
  108. 在ehcache中添加一个cache配置  
  109. <cache name="longTimeCache" maxElementsInMemory="2000" eternal="false"   
  110.        timeToIdleSeconds="300" timeToLiveSeconds="900"  
  111.        overflowToDisk="true" />  
  112.   
  113. 注意cache标签后面的 name 属性不要换行,换行了会有异常, 我上次不小心换行了, 查了半天文档都没有查到是什么问题,后来找个文件复制了一份对比才知道是换行引起的问题。  
  114.   
  115. 默认情况下二级缓存只会对load get 之类的方法缓存, 想list iterator 之类的方法也使用缓存 必须跟查询缓存一起使用, 在UserDaoImpl中重写listAll 方法。  
  116.     public List<User> listAll() {  
  117.     return getSession().createQuery("from User").setCacheable(true).list();  
  118.     }  

 log4j 配置文件中 设置成debug级别

在网页中访问http://localhost:8080/SSH2/user/userList.do

第一次访问可以看到debug信息如下:

[2013-04-13 22:00:08.082] [DEBUG] [http-8080-1] [org.hibernate.cache.internal.StandardQueryCache:137] - Query results were not found in cache

[2013-04-13 22:00:08.113] [DEBUG] [http-8080-1] [org.hibernate.SQL:104] - 

    select

        user0_.id as id1_0_,

        user0_.createTime as createTi2_0_,

        user0_.firstName as firstNam3_0_,

        user0_.userName as userName4_0_ 

    from

        t_user user0_

缓存中找不到 Query results were not found in cache 发出了查询sql

第二次访问:

Debug日志 

Checking query spaces are up-to-date: [t_user]

Returning cached query results

从缓存中找到了查询结果 直接返回了,没有发出查询sql

你可能感兴趣的:(spring+hibernate整合ehcache)