最近在开发一个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,过期设置为永不过期,因为过期数据需手动处理,
1 2 3 4 5 6 7 8 9 10 11 12
| <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 文件具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
| 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; } }
|
总结
看了Ehcache的相关文档后,发现其非常强大,而且使用起来非常简单,这里只是真对项目中的特定需求做了简单的使用,关于性能参数调优还有待优化完善,后期可能会用到分布式,集群等应用,使用的时候再进行总结学习。