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级别的缓存效果性能可能会更好。

  • 相关阅读:
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 133 克隆图
  • 原文地址:https://www.cnblogs.com/study-everyday/p/6377199.html
Copyright © 2011-2022 走看看