zoukankan      html  css  js  c++  java
  • spring整合ehcache注解实现查询缓存,并实现实时缓存更新或删除

    转载: http://www.importnew.com/23358.html

    写在前面:上一篇博客写了spring cache和ehcache的基本介绍,个人建议先把这些最基本的知识了解了才能对今天主题有所感触。不多说了,开干!

    注:引入jar

    <!-- 引入ehcache缓存 -->
    <dependency>
      <groupId>net.sf.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>2.8.3</version>
    </dependency>

    第一步:首先配置ehcache.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3          xsi:noNamespaceSchemaLocation="ehcache.xsd"
     4          updateCheck="true" monitoring="autodetect"
     5          dynamicConfig="true">
     6  
     7    <diskStore path="java.io.tmpdir"/>    
     8    <defaultCache
     9             maxEntriesLocalHeap="10000"
    10             eternal="false"
    11             overflowToDisk="false"
    12             timeToIdleSeconds="120"
    13             timeToLiveSeconds="120"
    14             diskSpoolBufferSizeMB="30"
    15             maxEntriesLocalDisk="10000000"
    16             diskExpiryThreadIntervalSeconds="120"
    17             memoryStoreEvictionPolicy="LRU">
    18         <persistence strategy="localTempSwap"/>
    19     </defaultCache>
    20  
    21     <cache name="myCache"
    22            maxEntriesLocalHeap="10000"
    23            maxEntriesLocalDisk="1000"
    24            eternal="false"
    25            diskSpoolBufferSizeMB="30"
    26            timeToIdleSeconds="300"
    27            timeToLiveSeconds="600"
    28            memoryStoreEvictionPolicy="LFU"
    29            transactionalMode="off">
    30         <persistence strategy="localTempSwap"/>
    31     </cache>   
    32 </ehcache>

    第二步:在spring.xml的配置文件中引入schema, xmlns:aop=”http://www.springframework.org/schema/aop” 和http://www.springframework.org/schema/cache  http://www.springframework.org/schema/cache/spring-cache-3.2.xsd

    缓存的配置:

     1 <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 -->
     2 <cache:annotation-driven cache-manager="ehcacheManager"/>
     3  
     4 <!-- cacheManager工厂类,指定ehcache.xml的位置 -->
     5 <bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
     6      <property name="configLocation" value="classpath:ehcache.xml" />
     7 </bean>
     8 <!-- 声明cacheManager -->
     9 <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    10      <property name="cacheManager" ref="ehcacheManagerFactory" />
    11 </bean>

    OK!缓存的相关配置已经完成。下面开始编写测试程序。这里需要连接数据库,我就不写了。这里为了方便就随便找了之前写过的model,这个model就是AOP注解实现日志管理的实体,为了偷懒就直接用了,希望你们不要误解,没有特殊意义的

    第三步:编写model,这里需要注意,要实现缓存的实体必须要序列化 private static final long serialVersionUID = -6579533328390250520L;  关于序列化的生成这里就不介绍了,大家可以百度看看。

      1 package org.shop.entity;
      2  
      3 import java.io.Serializable;
      4 import java.util.Date;
      5  
      6 public class SystemLog implements Serializable {
      7  
      8     private static final long serialVersionUID = -6579533328390250520L;
      9  
     10     private String id;
     11  
     12     private String description;
     13  
     14     private String method;
     15  
     16     private Long logType;
     17  
     18     private String requestIp;
     19  
     20     private String exceptioncode;
     21  
     22     private String exceptionDetail;
     23  
     24     private String params;
     25  
     26     private String createBy;
     27  
     28     private Date createDate;
     29  
     30     public String getId() {
     31         return id;
     32     }
     33  
     34     public void setId(String id) {
     35         this.id = id == null ? null : id.trim();
     36     }
     37  
     38     public String getDescription() {
     39         return description;
     40     }
     41  
     42     public void setDescription(String description) {
     43         this.description = description == null ? null : description.trim();
     44     }
     45  
     46     public String getMethod() {
     47         return method;
     48     }
     49  
     50     public void setMethod(String method) {
     51         this.method = method == null ? null : method.trim();
     52     }
     53  
     54     public Long getLogType() {
     55         return logType;
     56     }
     57  
     58     public void setLogType(Long logType) {
     59         this.logType = logType;
     60     }
     61  
     62     public String getRequestIp() {
     63         return requestIp;
     64     }
     65  
     66     public void setRequestIp(String requestIp) {
     67         this.requestIp = requestIp == null ? null : requestIp.trim();
     68     }
     69  
     70     public String getExceptioncode() {
     71         return exceptioncode;
     72     }
     73  
     74     public void setExceptioncode(String exceptioncode) {
     75         this.exceptioncode = exceptioncode == null ? null : exceptioncode.trim();
     76     }
     77  
     78     public String getExceptionDetail() {
     79         return exceptionDetail;
     80     }
     81  
     82     public void setExceptionDetail(String exceptionDetail) {
     83         this.exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim();
     84     }
     85  
     86     public String getParams() {
     87         return params;
     88     }
     89  
     90     public void setParams(String params) {
     91         this.params = params == null ? null : params.trim();
     92     }
     93  
     94     public String getCreateBy() {
     95         return createBy;
     96     }
     97  
     98     public void setCreateBy(String createBy) {
     99         this.createBy = createBy == null ? null : createBy.trim();
    100     }
    101  
    102     public Date getCreateDate() {
    103         return createDate;
    104     }
    105  
    106     public void setCreateDate(Date createDate) {
    107         this.createDate = createDate;
    108     }
    109 }

    第四步:编写dao,service

     1 package org.shop.dao;
     2  
     3 import org.shop.entity.SystemLog;
     4  
     5 public interface SystemLogMapper {
     6     int deleteByPrimaryKey(String id);
     7  
     8     int insert(SystemLog record);
     9  
    10     int insertSelective(SystemLog record);
    11  
    12     SystemLog selectByPrimaryKey(String id);
    13  
    14     int updateByPrimaryKeySelective(SystemLog record);
    15  
    16     int updateByPrimaryKey(SystemLog record);
    17  
    18     int count();
    19 }
     1 public interface SystemLogService {
     2  
     3     int deleteSystemLog(String id);
     4  
     5     int insert(SystemLog record);
     6  
     7     int insertTest(SystemLog record);
     8  
     9     SystemLog findSystemLog(String id);
    10  
    11     int updateSystemLog(SystemLog record);
    12  
    13     int count();
    14 }

    第五步:编写serviceImpl并添加缓存注解。这里缓存注解的参数不介绍了,不懂得看我上一篇博客,我这里先把需要的注解都写上了,一会一个一个介绍。

     1 @Service("systemLogService")
     2 public class SystemLogServiceImpl implements SystemLogService {
     3  
     4     @Resource
     5     private SystemLogMapper systemLogMapper;
     6  
     7     @Override
     8     public int deleteSystemLog(String id) {        
     9               return systemLogMapper.deleteByPrimaryKey(id);
    10     }
    11  
    12     @Override
    13     //@CachePut(value="myCache")
    14     //@CacheEvict(value="myCache",allEntries=true,beforeInvocation=true)
    15     @CacheEvict(value="myCache",key="0",beforeInvocation=true)
    16     public int insert(SystemLog record) {        
    17               return systemLogMapper.insertSelective(record);
    18     }
    19  
    20     @Override
    21     @Cacheable(value="myCache",key="#id")
    22     public SystemLog findSystemLog(String id) {        
    23              return systemLogMapper.selectByPrimaryKey(id);
    24     }
    25  
    26     @Override
    27     public int updateSystemLog(SystemLog record) {        
    28              return systemLogMapper.updateByPrimaryKeySelective(record);
    29     }
    30     @Override
    31     public int insertTest(SystemLog record) {        
    32            return systemLogMapper.insert(record);
    33     }
    34  
    35     @Override
    36     @Cacheable(value="myCache",key="0")
    37     public int count() {
    38            int num = systemLogMapper.count();
    39            return num;
    40     }
    41  
    42 }

    第六步:编写controller,即我们的测试。

     1 @Controller
     2 @RequestMapping("systemLogController")
     3 public class SystemLogController {
     4  
     5     @Resource
     6     private SystemLogService systemLogService;
     7  
     8     @RequestMapping("testLog")
     9     public ModelAndView testLog(){    
    10         ModelMap modelMap = new ModelMap();
    11         SystemLog systemLog = systemLogService.findSystemLog("c30e2398-079a-406b-a2f7-a85fa15ccac7");
    12         modelMap.addAttribute("data", systemLog);
    13         return new ModelAndView("index",modelMap);
    14     }
    15     @RequestMapping("insert")
    16     @ResponseBody
    17     public boolean Insert(SystemLog record){
    18         systemLogService.insert(record);
    19         return true;
    20     }
    21  
    22     @RequestMapping("test1")
    23     public ModelAndView test1(){
    24         ModelMap modelMap = new ModelMap();
    25         int num =systemLogService.count();
    26         modelMap.addAttribute("num", num);
    27         return  new ModelAndView("pageEhcache",modelMap);
    28     }
    29  
    30 }

    我们先测试查询的缓存,即serviceImpl中的 findSystemLog(String id) 方法,我们访问testLog.do,第一次运行如下图,注意控制台中的heap和 disk

    再一次访问testLog.do,运行你会发现没有访问数据库,如图:

    到此查询的缓存我们实现了,但是关于缓存的处理我们并没有做完,我们应该在深入思考下,在上面查询的缓存生命周期内,我们对刚才查询的表进行了增删改操作,这时我们再访问该查询方法,你会发现我们的数据并没有改变,还是增删改操作之前的数据(因为缓存的生命

    还在),这里是不是问题呢?此时我们需要对查询的缓存进行更新或删除。

     

    下面我们看serviceImpl中的insert方法和count()方法,count的方法是统计表中的数据总记录,insert方法是对该表进行新增一条记录,insert的缓存注解用的是@CacheEvict(value=”myCache”,key=”0″,beforeInvocation=true),这里清除的是指定缓存,也就是

    count方法中@Cacheable(value=”myCache”,key=”0″)的,(serviceImpl中注释的@CacheEvict(value=”myCache”,allEntries=true,beforeInvocation=true)是清除所有的缓存,这里我就不演示了,道理是一样的)

     

    这里我提供一个测试pageEhcache.jsp页面,

     1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
     2 <%
     3 String path = request.getContextPath();
     4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
     5 %>
     6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     7 <html>
     8   <head>
     9     <title>测试</title>  
    10     <script type="text/javascript" src="<%=request.getContextPath()%>/js/jquery-1.11.1.min.js"></script>
    11     <script type="text/javascript">
    12        function insert(){
    13            var record = $("#formID").serializeArray();
    14            console.info(record);
    15            $.ajax({
    16                    url : "<%=request.getContextPath()%>/systemLogController/insert.do",
    17                    type : 'post',
    18                    async:true, 
    19                    dataType:'json',
    20                    data : record,             
    21                    success:function(result){    
    22                        alert("插入成功!");
    23                    }
    24            });           
    25        }
    26     </script>
    27   </head>  
    28   <body>
    29   <h1><%=new Date()%></h1>
    30   <h1>这是一个练习</h1>
    31      <form id="formID" action="">
    32         id: <input name="id" type="text"/>
    33         <input type="button" value="插入" onclick="insert()"/>
    34     </form>
    35      
    36     总数:
    37     <h4>${num}</h4>
    38   </body>
    39 </html>

    我们先访问test1.do,看下表中的记录数并注意控制台变化

    页面显示如下,注意总数是67

    再一次访问test1.do,没有访问数据库,说明count()方法的缓存生效了,

    接下来开始新增记录,点击插入按钮

    注意控制台显示,这里执行了inserSQL语句,并remove了count()方法上的缓存,

    接下来再次访问test1.do,我们看到总数变化了,增加了一条,说明我们把之前count()方法上的缓存删除了,又执行了查询总数的sql

    再次访问test1.do,count()方法的缓存生效了,对吧!这个就是@CacheEvict注解的作用。

    在insert()方法上还有@CachePut(value=”myCache”)注解,上面的serviceImpl中注释了,它的作用是:@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

     

    我这里就不做演示了,你们可以自己动手试试。

     

    总结:我个人的理解,对查询方法增加缓存容易,但对于缓存的更新的处理就比较麻烦,我上面的serviceImpl中写了三种处理方式,

     

    1. 用@CachePut处理,这中方法需要对指定缓存key保持一致,尽管这样,还是不行,因为它返回的缓存是int(增加或删除或修改的记录数或是该记录的对象,这对我们查询所有或部分记录的缓存还是不可行的)
    2. 用@CacheEvict(value=”myCache”,key=”0″,beforeInvocation=true)处理,清除我们指定key的缓存,这种方式缺点是麻烦,需要我们注意每一个缓存的key
    3. 用@CacheEvict(value=”myCache”,allEntries=true,beforeInvocation=true)处理,清除所有缓存,这种方式最省事,但会把其他缓存也一同清除。

    随着业务的复杂性的不断增加,这些处理方式,可能会增加代码的复杂性,然后我想到的是对DB层进行缓存,可以利用redis,mamchched的进行处理。当然对于一般的web应用运用ehcache已经可以解决了,但是对大数据量的运用db级别的缓存效果性能可能会更好。

  • 相关阅读:
    如何成为一名专家级的开发人员
    ZapThink探讨未来十年中企业IT的若干趋势
    Adobe CTO:Android将超预期获50%份额
    我的美国之行
    用上Vista了!
    用pylint来检查python程序的潜在错误
    delegate in c++ (new version)
    The GNU Text Utilities
    python程序转为exe文件
    c++头文件,cpp文件,makefile,unit test自动生成器
  • 原文地址:https://www.cnblogs.com/study-everyday/p/6377199.html
Copyright © 2011-2022 走看看