一、需求分析

  调查问卷中或许每一个单击动作都会引发大量的数据库访问,特别是在参与调查的过程中,只是单击“上一页”或者“下一页”的按钮就会引发大量的查询,必须对这种问题进行优化才行。使用缓存策略进行查询缓存是降低数据库压力非常理想的方法,这里最起码能够有两种缓存方式:

  1.使用hibernate的二级缓存。

  2.使用spring自带的缓存模块进行查询缓存。使用spring自带的缓存模块功能必须要满足一下条件:

    (1)spring版本必须至少在3.1或以上,这里使用了spring3.1

    (2)必须要使用第三方缓存厂商的缓存支持,这里使用ehcache

  这里使用spring自带的缓存模块进行查询缓存。

二、集成spring的缓存模块实现对Service缓存代理,降低数据库压力

  1.引入类库

    [spring功能模块]

    spring-modules-cache.jar  

    [第三方缓存供应商] 

    backport-util-concurrent.jar
    com.springsource.org.apache.commons.logging-1.1.1.jar
    ehcache-1.5.0.jar
    jsr107cache-1.1.jar

  2.配置ehcache.xml配置文件,指定缓存的过期策略

 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<!-- 自定义一个缓存策略 -->
<cache name="surveyCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>

    上面配置中的属性意思都比较简单,很容易理解,不赘述。

  3.通过配置文件配置spring的缓存模块

    首先,必须必须引入缓存的命名空间才行,由于eclipse中并没有自带该命名空间相关信息,所以需要外部引入xsd约束,引入方式:

    Window->preferences->XML->XML catalog->Add找到spring-cache-3.1.xsd文件添加进来即可,由于对应的location已经失效,所以建议使用本地文件协议file:///替代http协议。

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/aop file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/beans file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/cache file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema\cache/spring-cache-3.1.xsd
http://www.springframework.org/schema/tx file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/context/spring-context-2.5.xsd">

  (1)ehcache工厂配置

 <!-- ehcacheManager工厂配置 -->
<bean id="ehcacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>

  (2)ehcache管理器配置

 <!-- ehcache管理器 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"></property>
</bean>

  (3)配置key生成器,这里需要自定义一个key生成器类,先存档,之后详解

<!-- Key生成器 ,先存档 -->
<bean id="surveyKeyGenerator" class="com.kdyzm.cache.SurveykeyGenerator" />

  (4)定义缓存通知,该配置的作用就是确定针对什么样的方法进行缓存,针对什么样的方法清空缓存。

 <!-- 定义缓存通知 -->
<cache:advice id="cacheAdvice" cache-manager="cacheManager"
key-generator="surveyKeyGenerator"><!-- 这里需要配置key生成器 -->
<cache:caching cache="surveyCache">
<!-- 设置缓存的方法 -->
<cache:cacheable method="get*" />
<cache:cacheable method="load" />
<cache:cacheable method="find*" />
<cache:cacheable method="is*" /> <!-- 设置需要清空缓存的方法 -->
<cache:cache-evict method="save*" all-entries="true" />
<cache:cache-evict method="update*" all-entries="true" />
<cache:cache-evict method="delete*" all-entries="true" />
<cache:cache-evict method="batch*" all-entries="true" />
<cache:cache-evict method="create*" all-entries="true" />
<cache:cache-evict method="new*" all-entries="true" />
</cache:caching>
</cache:advice>

  (5)配置缓存AOP,创建切入点表达式,确定缓存对象的范围

    为了将缓存通知首先启动,将其order属性配置为0(并不是因为0才首先启动,只是相对于日志通知和事务通知来说其order属性值最小)。

 <aop:config>
<!-- 日志切入点 -->
<aop:pointcut
expression="(execution(* *..*Service.save*(..))
or execution(* *..*Service.update*(..))
or execution(* *..*Service.delete*(..))
or execution(* *..*Service.batch*(..))
or execution(* *..*Service.create*(..))
or execution(* *..*Service.new*(..))) and !bean(logService)"
id="loggerPointcut" />
<aop:pointcut expression="execution(* *..*Service.*(..))"
id="txPointcut" />
<!-- 必须配置order属性,使用该属性可以改变配置的通知的加载顺序,order值越大,优先级越高 必须让事务的通知放到后面,让日志的通知先执行,这样才能在执行完成日志的通知后事务确保能够结束。
order值越小,优先级越高 为了解决事务没有结束的问题,必须同时修改解除绑定的时间 -->
<aop:advisor advice-ref="cacheAdvice"
pointcut="execution(* com.kdyzm.service.SurveyService.*(..)) or
execution(* com.kdyzm.service.PageService.*(..)) or
execution(* com.kdyzm.service.QuestionService.*(..)) or
execution(* com.kdyzm.service.AnswerService.*(..))" order="0" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"
order="2" />
<aop:aspect id="loggerAspect" ref="logger" order="1">
<aop:around method="record" pointcut-ref="loggerPointcut" />
</aop:aspect>
</aop:config>

  这里对调查相关的所有Service中的相关方法都进行了代理缓存。

  4.如何自定义key生成器

    配置文件中有一个key生成器的配置,该配置的作用就是根据当前执行的方法环境(方法名、参数列表、类名)计算出来唯一的标识符(key值),如果该标识符已经存在,则缓存管理器就会调用缓存中的数据否则就执行目标方法并将目标方法的查询结果缓存起来。

 package com.kdyzm.cache;

 import java.lang.reflect.Method;

 import org.springframework.cache.interceptor.KeyGenerator;

 /**
* 自定义key生成器
* @author kdyzm
*
*/
public class SurveykeyGenerator implements KeyGenerator{ //什么对象调用的什么方法,参数列表是什么
@Override
public Object generate(Object arg0, Method arg1, Object... arg2) {
String targetCode=arg0.getClass().getSimpleName()+"["+arg0.hashCode()+"]";    //arg0是类
String methodName=arg1.getName();                            //arg1是方法
if(arg2!=null){                                       //arg2是参数列表
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append("(");
for(int i=0;i<arg2.length;i++){
stringBuffer.append(arg2[i].toString());
stringBuffer.append(",");
}
stringBuffer.append(")");
targetCode= targetCode+"."+methodName+stringBuffer.toString();
System.out.println(targetCode);
return targetCode;
}
targetCode= targetCode+"."+methodName+"()";
System.out.println(targetCode);
return targetCode;
}
}

三、测试效果

  1.在主页上单击参与调查,查看后台

  

  清空控制台,重新单击一次“参与调查”超链接,再次查看后台,这时候就会发现没有SQL语句发出了(手要快,不要超过120秒,之前配置的ehcach.xml配置文件中声明了如果超过120s没用的话就会清空缓存,所以还是会发出SQL查询语句)

  2.测试参与调查的过程中的缓存效果。

    这里需要创建多个调查页,在翻页的过程中查看缓存的效果,这里我的调查1中一共有三页。

    (1)单击调查1,依次单击下一页,直到最后一页,观察控制台打印,发现不断地有SQL查询发出

  

  

    (2)单击上一页、直到第一页,还是发现不断的有查询发出。

    (3)从第一页单击“下一页”直到最后一页,发现不再有查询发出,单击上一页还是没有发现有SQL语句发出,证明spring缓存配置成功。

  

  

【Java EE 学习 78 上】【数据采集系统第十天】【Service使用Spring缓存模块】的更多相关文章

  1. 【Java EE 学习 74 上】【数据采集系统第六天】【使用Jfreechart的统计图实现】【Jfreechart的基本使用方法】

    之前已经实现了数据的采集,现在已经有了基本的数据,下一步就需要使用这些数据实现统计图的绘制了.这里使用Jfreechart实现这些统计图的绘制.首先看一下Jfreechart的基本用法,只有知道了它的 ...

  2. 【Java EE 学习 78 中】【数据采集系统第十天】【Spring远程调用】

    一.远程调用概述 1.远程调用的定义 在一个程序中就像调用本地中的方法一样调用另外一个远程程序中的方法,但是整个过程对本地完全透明,这就是远程调用.spring已经能够非常成熟的完成该项功能了. 2. ...

  3. 【Java EE 学习 80 上】【WebService】

    一.WebService概述 什么是WebService,顾名思义,就是基于Web的服务,它使用Http方式接收和响应外部系统的某种请求,从而实现远程调用.WebService实际上就是依据某些标准, ...

  4. 【Java EE 学习 25 上】【网上图书商城项目实战】

    一.概述 1.使用的jdk版本:1.6 2.java EE版本:1.6 3.指导老师:传智播客 王建 二.小项目已经实现的功能 普通用户: 1.登陆 2.注册 3.购物 4.浏览 管理员用户(全部管理 ...

  5. 【Java EE 学习 77 上】【数据采集系统第九天】【通过AOP实现日志管理】【通过Spring石英调度动态生成日志表】【日志分表和查询】

    一.需求分析 日志数据在很多行业中都是非常敏感的数据,它们不能删除只能保存和查看,这样日志表就会越来越大,我们不可能永远让它无限制的增长下去,必须采取一种手段将数据分散开来.假设现在整个数据库需要保存 ...

  6. 【Java EE 学习 76 上】【数据采集系统第八天】【角色授权】【用户授权】【权限的粗粒度控制】【权限的细粒度控制】

    一.角色管理 单击导航栏上的"角色管理"超链接,跳转到角色管理界面,在该界面上显示所有角色,并提供角色的增加和删除.修改超链接. 1.增加新角色(角色授权) 流程:单击增加新角色超 ...

  7. 【Java EE 学习 72 上】【数据采集系统第四天】【增加调查logo】【文件上传】【动态错误页指定】【上传限制】【国际化】

    增加logo的技术点:文件上传,国际化 文件上传的功能在struts2中是使用文件上传拦截器完成的. 1.首先需要在页面上添加一个文件上传的超链接. 点击该超链接能够跳转到文件上传页面.我给该表单页面 ...

  8. 【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】

    一.权限计算相关分析 1.如何存储权限 首先说一下权限保存的问题,一个系统中最多有多少权限呢?一个大的系统中可能有成百上千个权限需要管理.怎么保存这么多的权限?首先,我们使用一个数字中的一位保存一种权 ...

  9. 【Java EE 学习 71 上】【数据采集系统第三天】【增加页面】【增加问题】【编辑页面,编辑问题】

    增加页面和编辑页面.增加问题和编辑问题的页面使用的都是相同的页面,最后调用的方法是saveOrUpdate方法,所以只说一个就可以了. 一.增加页面 比较简单,略.流程如下: 单击“增加页”超链接-& ...

随机推荐

  1. Android 热修复方案Tinker

    转自:http://blog.csdn.net/l2show/article/details/53925543 Android 热修复方案Tinker(一) Application改造 Android ...

  2. Oracle以15分钟为界,统计一天内各时间段的数据笔数

    db.table替换为自己的表名,StartTime为date字段 select count(*), (case floor((to_char(StartTime,'mi'))/15) when 0 ...

  3. 机器学习——利用K-均值聚类算法对未标注数据分组

    聚类是一种无监督的学习,它将相似的对象归到同一簇中.它有点像全自动分类.聚类方法几乎可以应用到所有对象,簇内的对象越相似,聚类的效果越好. K-均值(K-means)聚类算法,之所以称之为K-均值是因 ...

  4. MySQL点滴

    1. 只安装Server和Workbench即可: 2. 安装时安装Windows服务,可以在“管理 > 服务”中开启关闭服务: 3. mysql -uroot -p1234 4. PHP Fa ...

  5. svn 图标不显示

    1.判断注册表里面是否有 SVN图标信息 方法:输入:win+R,输入regedit,调出注册表信息,按下Ctrl+F,在注册表里搜索"ShellIconOverlayIdentifiers ...

  6. js ES6 多行字符串 连接字符串

    1. 以前,js多行字符串用\n写起来比较费事,所以最新的ES6标准新增了一种多行字符串的表示方法,用` ... `表示: 旧版写法 alert("你好,\n 我叫\n Olive" ...

  7. 兼容好的JS图片上传预览代码

    转 : http://www.codefans.net/articles/1395.shtml 兼容好的JS图片上传预览代码 (谷歌,IE11) <html xmlns="http:/ ...

  8. Ajax我选择这样入门

    什么是AJAX? AJAX的意思就是异步的JavaScript和XML.简而言之,它是使用XMLHttpRequest对象与服务器端通信的脚本语言.它可以发送及接收各种格式的信息,包括JSON.XML ...

  9. Python - 类与对象的方法

    类与对象的方法

  10. php数组array_push()和array_pop()以及array_shift()函数

    <?php /** * array_push()将一个或多个单元压入数组的末尾(入栈) */ $stack = array("Java", "Php", ...