hibernate二级缓存之ehcache初探

[b] 一、Ehcache简介[/b]
EhCache是Hibernate的二级缓存技术之一,可以把查询出来的数据存储在内存或者磁盘,节省下次同样查询语句再次查询数据库,大幅减轻数据库压力;
当用Hibernate对关系型数据库表进行更改时(DELETE/UPDATE),这时EhCache会自动把缓存中关于此表的所有缓存全部删除掉,以此来达到同步效果。基于这一点来说,ehcache不适合那种经常修改数据库表的情形。
Ehcache适用场合:
[list]
[*]1)对数据库表很少修改;
[*]2)对并发要求不是很严格。
[/list]
对于工业传感器实时数据,程序对其保存后,利用二级缓存技术查看历史数据。我本人也是基于这种场景才用ehcache的
[b]二、准备工作[/b]
[list]
[*]ehcache-core.jar ehcache核心包,在maven项目中,类似于如下引入

<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.3</version>
</dependency>

[*]ehcache-spring-annotations 基于spring注解ehcache,在maven项目中,类似于如下引入

<groupId>com.googlecode.ehcache-spring-annotations</groupId>
<artifactId>ehcache-spring-annotations</artifactId>
<version>1.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

[*]其他jar包(例如hibernate系列、spring web系列,commons系列)
[/list]
[b]三、Ehcache.xml配置[/b]
Ehcache.xml文件时ehcache二级缓存最主要的我配置文件,它定义了对哪些实体对象进行缓存,以及缓存策略,直接上一个配置片段把
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<cache name="entity.HistoryData"
maxElementsInMemory="5000" eternal="false" timeToIdleSeconds="300"
timeToLiveSeconds="7200" overflowToDisk="false" />
</ehcache>


[table]
| name|要缓存的实体类的名称|
| maxElementsInMemory|设置该缓存实体的最大个数|
| eternal|对象是否永久有效|
| timeToIdleSeconds|设置对象在失效前的允许闲置时间(单位:s)|
| timeToLiveSeconds|设置对象在失效前允许存活时间(单位:s)|
| overflowToDisk|当缓存中对象达到maxElementsInMemory时,存入磁盘|
| diskSpoolBufferSizeMB|设置磁盘缓冲区大小|
| maxElementsOnDisk|设置磁盘能缓存最大对象个数|
| diskPersistent|是否缓存虚拟机重启期数|
| diskExpiryThreadIntervalSeconds|磁盘失效线程运行时间间隔,默认是120秒。|
| memoryStoreEvictionPolicy|当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 |
| clearOnFlush|内存数量最大时是否清除。 |
[/table]
两个问题:
[list]
[*]该文件放置在那里?该文件可以放置在工程的任意位置
[*]该文件如何引入?或者说ehcache.xml路径是如何确定的?
[/list]
我们可以通过查阅相关源码,可知
在hibernate.cache.provider所指定的类net.sf.ehcache.hibernate.EhCacheRegionFactory类的抽象类AbstractEhcacheRegionFactory中,对NET_SF_EHCACHE_CONFIGURATION_RESOURCE_NAME中有明确的解释:

/**
The Hibernate system property specifying the location of the ehcache configuration file name.
If not set, ehcache.xml will be looked for in the root of the classpath.
If set to say ehcache-1.xml, ehcache-1.xml will be looked for in the root of the classpath.
**/

[/list]
[b]四、集成到spring[/b]
这一个步骤分为两部分,一部分是对ehcache打开注解功能,另一部分是集成hibernate sesionFactory中
[list]
[*]
配置注解,新建spring-ehcache.xml,并在web.xml param中引入,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
<ehcache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
<ehcache:config cache-manager="cacheManager"/>
</beans>

[i]注:对于命名空间,前提是引入ehcache-spring-annotations.jar包,否则提示无法解析该命名空间。ConfigLocation指定ehcache.xml配置文件所在的路径。[/i]
[*]hibernate sessionFactory配置,新建spring-sessionFactory.xml,并在web.xml中引入,如下
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang" xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:property-placeholder location="classpath:/resource.properties" />

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="idleConnectionTestPeriod" value="120"/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="schemaUpdate" value="${hibernate.schemaUpdate}"/>
<property name="packagesToScan" value="${hibernate.packageScan}"/>
<property name="hibernateProperties">
<value>
hibernate.dialect ${hibernate.dialect}
hibernate.show_sql ${hibernate.show_sql}
hibernate.cache.region.factory_class ${hibernate.cache.provider}
hibernate.cache.use_second_level_cache ${hiberante.second.cache}
[color=red]Hibernate.cache.use_query_cache true [/color]
</value>
</property>
</bean>
</beans>

[i]其中,
[list]
[*]hibernate.cache.provider 选择二级缓存实现的类
[*]Hibernate.cache.use_second_level_cache:选择是否开启二级缓存
[*][color=red]Hibernate.cache.use_query_cache[/color] 是否开启查询缓存(重要,后面讲到)
[/list][/i]
[/list]
[b]五、测试[/b]
新建一个实体类
package entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Table(name="history_data")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class HistoryData implements Serializable{
//省略
}

把这个类映射到数据库表中。并且设置缓存方式

缓存方式有四种
[quote="参考资料"]CacheConcurrencyStrategy.NONE
   CacheConcurrencyStrategy.READ_ONLY ,只读模式,在此模式下,如果对数据进行更新操作,会有异常;
   CacheConcurrencyStrategy.READ_WRITE ,读写模式在更新缓存的时候会把缓存里面的数据换成一个锁,其它事务如果去取相应的缓存数据,发现被锁了,直接就去数据库查询;
   CacheConcurrencyStrategy.NONSTRICT_READ_WRITE ,不严格的读写模式则不会的缓存数据加锁;
   CacheConcurrencyStrategy.TRANSACTIONAL ,事务模式指缓存支持事务,当事务回滚时,缓存也能回滚,只支持 JTA 环境。

缓存的注释写法如下,加在 Entity 的 java 类上:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
[/quote]
如果我们要对hql查询设置缓存,可以通过设置this.getHibernateTemplate().setCacheQueries(boolean)来实现,前提是开启查询缓存。下面是一个例子:
public List<HistoryData> list(String name,String location,Date startTime,
Date endTime, boolean alarm,int start,int limit){
String hql = "from HistoryData hd where 1=1 ";
if(StringUtils.isNotBlank(name)){
hql+= " and hd.name like '%"+name+"%' ";
}
if(StringUtils.isNotBlank(location)){
hql+= " and hd.location like '"+location+"' ";
}
this.getHibernateTemplate().setCacheQueries(true);
List<HistoryData> hds = this.findByNamedParam(hql, null, null, start, limit);
this.getHibernateTemplate().setCacheQueries(false);
return hds;
}


[i] 调用这个方法,针对同一sql来讲,只发送一条sql,下次查询直接从缓存中获取。
注:this.getHibernateTemplate().setCacheQueries(true);后最好是要this.getHibernateTemplate().setCacheQueries(false),来关闭查询缓存,因为实际应用中,不可能所有的查询我们都得设置缓存。[/i]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值