优化 应用程序缓存

应用程序缓存包括:对象缓存、查询缓存、页面缓存
页面缓存包括:动态页面静态化、servlet缓存、页面内部缓存
对象缓存
由hibernate框架提供,细粒度的缓存数据库的查询结果,无需手动编码实现,(也可以不实用hibernate,而是自己实现对象缓存如将查询出的对象放入hashMap中等),是最省事的缓存策略,使用对象缓存会极大的降低web系统对数据库的访问量。
对象缓存适合联机事务处理(OLTP)
对象缓存分为:对表记录的entity对象缓存、对1n关系集合的缓存、对n对1关系关联对象的缓存。
hibernate对象缓存的配置
@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }
注:NonstrictReadWriteCache
  Caches data that is sometimes updated without ever locking the cache. If concurrent access to an item is possible, this concurrency strategy makes no guarantee that the item returned from the cache is the latest version available in the database. Configure your cache timeout accordingly! This is an "asynchronous" concurrency strategy.
有时更新缓存数据时无需锁住该缓存,如果可能对一个项目进行并发性的访问,那么这种并发的策略使得缓存返回数据库最新版本数据无法得到保证。这个是一个异步的缓存策略。
配置关联集合的缓存
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() { return tickets; }
注:在返回一所关联的多个对象上添加异步缓存的注解
仅仅添加Annotation就可以了,无须编码,即可自动享受对象缓存。Hibernate会拦截对象的CRUD操作,针对对象读取操作进行缓存,针对对象修改操作自动清理缓存
Hibernate二级缓存
Hibernate二级缓存是提升web应用性能的法宝,OLTP类型的web应用,由于应用服务器端可以进行群集水平扩展,最终的系统瓶颈总是逃不开数据库访问;
哪个框架能够最大限度减少数据库访问,降低数据库访问压力,哪个框架提供的性能就更高;
针对数据库的缓存策略:对象缓存、查询缓存、应用于数据时时话不高的情况。
查询缓存是对查询结果进行缓存,类似数据库的Query Cache,适用于一些耗时,但是时时性要求不高的情景。查询缓存和对象缓存是互补的。
当查询结果集涉及到的记录表被修改后需要注意清理缓存。
配置hibernate的查询缓存
在配置文件中打开Query Cache
hibernate.cache.use_query_cache true
在查询的时候显式编码使用Cache
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger") .setEntity("blogger",blogger) .
setMaxResults(15) .
setCacheable(true) .
setCacheRegion("frontpages") .
list();
Hibernate查询缓存特征
并非缓存整个查询结果集,而是缓存查询结果集的entity对象id。
entity对象的id集合
[blogId1, blogId2, blogId3,…]
在遍历结果集的时候,再按照blogId去查询blog对象,例如 select blog.* from blog where id=?
如果此时blog配置了对象缓存,则自动读取对象缓存
Hibernate查询缓存会自动清理过期缓存
一旦结果集涉及的entity被修改,查询缓存就被自动清理
页面缓存
页面缓存的作用是什么?
1.针对页面的缓存技术不但可以减轻数据库服务器压力,还可以减轻应用服务器压力
2.好的页面缓存可以极大提高页面渲染速度
3.页面缓存的难点在于如何清理过期的缓存
页面缓存技术有哪些?
1.动态页面静态化
2.Servlet缓存
3.页面局部缓存
动态页面静态化
利用模版技术将访问过的动态页面生产静态的html,同时修改链接,下一次请求直接访问静态链接页面。
动态页面静态化技术的广泛应用于互联网CMS/新闻类Web应用,但也有BBS应用使用该技术,例如Discuz!
缺点:
无法进行权限验证,无法显示个性化信息
可以使用AJAX请求弥补动态页面静态化的某些缺点
Servlet缓存
针对URL访问 返回的页面结果进行缓存,适用于粗粒度的页面缓存,例如新闻发布
OScache提供了简单的Servlet缓存(通过web.xml中的配置)
也可以自己编程实现Servlet缓存
实例
<filter>
    <filter-name>CacheFilter</filter-name>
    <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
    <init-param>
        <param-name>time</param-name>
        <param-value>600</param-value>
    </init-param>
    <init-param>
        <param-name>scope</param-name>
        <param-value>session</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CacheFilter</filter-name>
    <url-pattern>/news/*</url-pattern>
</filter-mapping>

页面局部缓存

针对动态页面的局部片断内容进行缓存,适用于一些个性化但不经常更新的页面(例如博客)
OSCache提供了简单的页面缓存
可以自行扩展JSP Tag实现页面局部缓存
实例:
<%@ taglib uri="http://www.opensymphony.com/oscache" prefix="cache" %>
<cache:cache>
     ... some jsp content ...
</cache:cache>

<cache:cache key="foobar" scope="session">
     ... some jsp content ...
</cache:cache>

<cache:cache key="<%= product.getId() %>" time="1800" refresh="<%= needRefresh %>">
     ... some jsp content ...
</cache:cache>

<cache:cache key="<%= product.getId() %>" cron="0 2 * * *" refresh="<%= needRefresh %>">
     ... some jsp content ...
</cache:cache>

EHCache
适合充当对象缓存和Hibernate集成效果很好,Gavin King也是EHCache作者之一
OSCache
充当Servlet和页面缓存
在一个Web应用当中可以同时使用OSCache和EHCache
JBossCache
在Java群集环境下使用
支持缓存在节点之间的复制,在JBoss AS上被用来实现HTTP Session的内存复制功能
非Java实现的通用缓存产品
Memcached
在大规模互联网应用下使用
每秒支撑1.5万~2万次请求
Tokyo Tyrant  
兼容memcached协议,可以持久化存储
支持故障切换,对缓存服务器有高可靠性要求可以使用
每秒支撑0.5万~0.8万次请求
基于AJAX技术的浏览器缓存
使用AJAX调用的时候,将数据库在浏览器端缓存
只要不离开当前页面,不刷新当前页面,就可以直接读取缓存数据
只适用于使用AJAX技术的页面

未使用ajax缓存代码
<script src="jQuery.js"></script> 
   2.   <script language="JavaScript"> 
   3.   <!-- 
   4.     function gopage(option,obj){ 
   5.     var page = $("#page").html() * 1; 
   6.     obj.disabled = true; 
   7.     if(option == '+'){ 
   8.         page ++ ; 
   9.         var url = "data.php?page="+page + "&r="+Math.random();//使用ajax要加上时间戳或是随机数,如Math.random()或是new Date() 
  10.      //获取ajax url,后面的random是为了防止浏览器缓存xml内容 
  11.     }else{ 
  12.         page --; 
  13.         if(page < 1)page =1; 
  14.         var url = "data.php?page="+page + "&r="+Math.random(); 
  15.  
  16.     } 
  17.     $("#data").html("loading...");//设置loading状态 
  18.     $("#page").html(page); 
  19. //下面是ajax处理 
  20.     $("#data").load(url, 
  21.         {limit: 25},  //此处为传递给服务器端的参数
  22.              function() { obj.disabled = false; } 
  23.         ); 
  24.  
  25.     } 
  26.   //--> 
  27.   </script> 
  28. <input value="<" onclick="gopage('-',this)" type="button">//传递this不需要加'' 
  29. <input value=">" onclick="gopage('+',this)" type="button"> 
  30.   page:<span id="page">1</span> 
  31. <div style="border: 2px solid red; padding: 2px;" id="data">data area</div>
注:load方法默认为get方式,当传递数据时使用post方式。
使用ajax的缓存代码# <script language="JavaScript"> 
#   <!-- 
# var cache_data = new Array();//定义全局变量用来保存缓存数据
      //使用new Array定义全局的数组
#     function gopageCache(option,obj){ 
#     var page = $("#page2").html() * 1;   
#     if(option == '+'){ 
#         page ++ ; 
#         var url = "data.php?page="+page + "&r="+Math.random(); 
#     }else{ 
#         page --; 
#         if(page < 1)page =1; 
#         var url = "data.php?page="+page + "&r="+Math.random(); 
#  
#     } 
# /*下面是缓存增加的部分*/ 
//先从缓存中查找
#     if( (cache_data[page] !=null) && (cache_data[page].length > 1) ) { 
# //如果缓存存在,则直接调用缓存数据,不用再去服务器进行数据请求 
#         alert('cache hit'); 
#         $("#data2").html(cache_data[page]); 
#         $("#page2").html(page); 
#         return true; 
#     } 
#     $("#page2").html(page); 
#     obj.disabled = true; 
#     $("#data2").html("loading(cache enabled)...");   
#     $("#data2").load(url, 
#         {limit: 25},  //逐条缓存的
#              function(responseText) { obj.disabled = false; 
#                             cache_data[page] = responseText;//将当前的数据存入到内存(缓存变量)中 } 
#         ); 
#  
#     } 
#  
#   //--> 
#   </script> 
# <input value="<" onclick="gopageCache('-',this)" type="button"> 
# <input value=">" onclick="gopageCache('+',this)" type="button"> 
#   page:<span id="page2">1</span> 
# <div style="border: 2px solid red; padding: 2px;" id="data2">data area</div>
基于HTTP协议的资源缓存
使用实例
<filter>
    <filter-name>CacheFilterStaticContent</filter-name>
    <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
    <init-param>
        <param-name>expires</param-name>
        <param-value>time</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CacheFilterStaticContent</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>

猜你喜欢

转载自jameszhao1987.iteye.com/blog/1270893
今日推荐