最近在開發一個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;
}
}