最近在开发一个android项目,项目是面向在校大学生的,据说推广起来,访问量必将很大,针对这种情况,再看看我们现在有的后台服务框架,竟然没有针对高访问量这种情况的处理,这里必定用到缓存技术,现有的框架中也最多存在Hibernate缓存的使用,但针对数据层的缓存,必然会用到Hibernate的二级缓存,竟然框架中连Hibernate的二级缓存都没用过,看到这些,想想也没有在现有的基础上做简单扩展的必要了,于是决定针对后台服务缓存这层进行研究使用。
在网上看到了不少缓存技术,有些比较陌生,有些不适合现有项目,还有些使用上不是很方便,最终确定选择了ehcache,发现Hibernate的二级缓存就是使用Ehcache实现的,但毕竟是嵌套在Hibernate框架中的,使用的灵活性就大打折扣了,例如Hibernate的二级缓存对于查询列表只能针对固定不变的结果数据进行缓存,另外不支持对缓存的动态添加修改,Ehcache本身单独就是很强大,于是决定单独提出来使用。
Ehcache 是现在最流行的纯Java开源缓存框架,配置简单、结构清晰、功能强大。
关于Ehcache原理性的东西这边就不做详细的记录了,毕竟也是刚刚接触,理解的多会有偏差,记录下一篇比较详细的文章供以后参考:
http://raychase.iteye.com/blog/1545906
下面介绍项目中Ehcache的简单使用。
前期准备
项目现有环境,eclipse开发,spring4.0
1、从官网上下载Ehcache最新版本ehcache-2.8.3-distribution,解压文件将lib下的三个jar包 拷到项目中(明显看到所需jar包都很小)
2、将ehcache.xml文件考到项目src根目录下
文件配置
ehcache.xml文件配置
增加cache节点,这里由于项目需求,设置最大缓存数量maxElementsInMemory为100000,过期设置为永不过期,因为过期数据需手动处理,
<cachename="jobInfoListCache"
maxElementsInMemory="100000" //最大缓存数量
eternal="true" //永不过期,手动处理过期数据
overflowToDisk="false"> //内存超出时不放到磁盘
<searchableallowDynamicIndexing="true">
<searchAttributename="positionTitle"expression="value.getPositionTitle()"/>
<searchAttributename="cityCode" expression="value.getCityCode()"/>
<searchAttributename="distinctCode"expression="value.getDistinctCode()"/>
<searchAttributename="positionTypeId"expression="value.getPositionTypeId()"/>
<searchAttributename="releaseTime"expression="value.getReleaseTime()"/>
</searchable>
</cache>
applicationContext-services.xml文件配置
<!--缓存配置 -->
<beanid="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<propertyname="configLocation"value="classpath:ehcache.xml"/>
<propertyname="shared" value="true"/>
</bean>
<!-- 配置一个缓存处理接口类-->
<beanid="jobInfoCacheManager"class="com.quangao.service.cacheManager.JobInfoCacheManager">
<propertyname="cacheManager"ref="cacheManager"/>
<propertyname="_dao" ref="GenericDao" />
</bean>
具体使用
JobInfoCacheManager 文件具体实现
package com.quangao.service.cacheManager;
import java.util.ArrayList;
import java.util.List;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.search.Attribute;
import net.sf.ehcache.search.Direction;
import net.sf.ehcache.search.Query;
import net.sf.ehcache.search.Result;
import net.sf.ehcache.search.Results;
import com.quangao.dao.generic.GenericDao;
import com.quangao.model.Enum.EnumStatusType;
import com.quangao.model.jobposition.TJobPosition;
import com.quangao.util.StringUtil;
public class JobInfoCacheManager {
private CacheManagercacheManager;
private GenericDao _dao;
private final String attrNames[] = {"positionTitle", "cityCode","distinctCode","positionTypeId", "releaseTime" };
/**
* 获取职位列表
*
* @return
*/
public List<TJobPosition> getTJobPositions()
{
String hql = "fromTJobPosition where 1=1 and handleStatusId='"
+ EnumStatusType.FB.getKey() +"' order by releaseTime desc";
return_dao.getHql(hql);
}
/**
*
* 初始化职位列表缓存
*
*/
public void initJobInfoCache()
{
Cache cache = cacheManager.getCache("jobInfoListCache");
// 初始化列表数据
List<TJobPosition> jobPositions = getTJobPositions();
if (jobPositions !=null && jobPositions.size() > 0)
{
TJobPosition tJobPosition = null;
for (int i = 0; i < jobPositions.size(); i++)
{
tJobPosition = jobPositions.get(i);
Element element = new Element(tJobPosition.getId(),
tJobPosition);
cache.put(element);
}
}
// 动态注册搜索项,不起作用,研究中
//cache.registerDynamicAttributesExtractor(new
//DynamicAttributesExtractor() {
// public Map<String,Object> attributesFor(Element element) {
// Map<String, Object> attrs= new HashMap<String, Object>();
// TJobPosition value =(TJobPosition)element.getObjectValue();
// attrs.put(attrNames[0],value.getPositionTitle());
// attrs.put(attrNames[1],value.getCityCode());
// attrs.put(attrNames[2],value.getDistinctCode());
// attrs.put(attrNames[3],value.getPositionTypeId());
// return attrs;
// }
// });
}
/**
* 增加职位缓存
*
* @param tJobPosition
*/
public void addJobInfoCache(TJobPosition tJobPosition)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
if (tJobPosition !=null)
{
Element element = new Element(tJobPosition.getId(), tJobPosition);
cache.put(element);
}
}
/**
* 修改职位缓存
*
* @param tJobPosition
*/
public void updateJobInfoCache(TJobPosition tJobPosition)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
if (tJobPosition !=null)
{
// 相同key值,内容会被覆盖
Element element = new Element(tJobPosition.getId(), tJobPosition);
cache.put(element);
}
}
/**
* 移除职位缓存
*
* @param tJobPosition
*/
public void removeJobInfoCache(TJobPosition tJobPosition)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
if (tJobPosition !=null)
{
cache.remove(tJobPosition.getId());
}
}
/**
* 根据条件查询缓存列表
*
* @param cityCode
* @param areaCode
* @param typeCode
* @param firstResult
* @param maxResult
* @return
*/
public List<TJobPosition>getJobPositionsByCondition(String positionTitle,
String cityCode, String areaCode, String typeCode,
Integer firstResult, Integer maxResult)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
List<TJobPosition> listTJobPositions = newArrayList<TJobPosition>();
/**
*
* 这是新版本的强大之处,可以根据缓存值对象进行条件查询,前提是在ehcache.xml文件中对值对象查询字段进行定义搜索项
*<searchableallowDynamicIndexing="true">
<searchAttributename="positionTitle"expression="value.getPositionTitle()"/>
<searchAttribute name="cityCode"expression="value.getCityCode()"/>
<searchAttribute name="distinctCode"expression="value.getDistinctCode()"/>
<searchAttribute name="positionTypeId"expression="value.getPositionTypeId()"/>
<searchAttribute name="releaseTime"expression="value.getReleaseTime()"/>
</searchable>
*/
Attribute<String> positionTitlet = cache
.getSearchAttribute(attrNames[0]);
Attribute<String> cityCodet = cache.getSearchAttribute(attrNames[1]);
Attribute<String> areaCodet = cache.getSearchAttribute(attrNames[2]);
Attribute<String> typeCodet = cache.getSearchAttribute(attrNames[3]);
Attribute<String> releaseTime =cache.getSearchAttribute(attrNames[4]);
// 查询结果集
Results results = null;
// 新建缓存值查询
Query query = cache.createQuery().includeValues();
// 根据条件索引
if (StringUtil.isNotBlankOrNull(positionTitle))
{
query.addCriteria(positionTitlet.ilike("*" +positionTitle +"*"));
}
if (StringUtil.isNotBlankOrNull(cityCode))
{
query.addCriteria(cityCodet.eq(cityCode));
}
if (StringUtil.isNotBlankOrNull(areaCode))
{
query.addCriteria(areaCodet.eq(areaCode));
}
if (StringUtil.isNotBlankOrNull(typeCode))
{
query.addCriteria(typeCodet.eq(typeCode));
}
// 查询结果排序
query.addOrderBy(releaseTime, Direction.DESCENDING).end();
results = query.execute();
// 分页查找
// List<Result>listreResults = results.all();
List<Result> listreResults = results.range(firstResult,maxResult);
// 将结果封装成需要的数据格式
if (listreResults !=null && listreResults.size() > 0)
{
Result result = null;
for (int i = 0; i < listreResults.size(); i++)
{
result = listreResults.get(i);
System.out.println("+++++++++++" + result.toString());
listTJobPositions.add((TJobPosition)result.getValue());
}
}
System.out.println("===============" + results.size());
return listTJobPositions;
}
public GenericDao get_dao()
{
return_dao;
}
public void set_dao(GenericDao dao)
{
_dao = dao;
}
public CacheManager getCacheManager()
{
returncacheManager;
}
public void setCacheManager(CacheManager cacheManager)
{
this.cacheManager = cacheManager;
}
}