spring整合ehcache注解实现查询缓存,并实现实时缓存更新或删除

注:引入jar

1
2
3
4
5
6
<!-- 引入ehcache缓存 -->
< dependency >
< groupId >net.sf.ehcache</ groupId >
< artifactId >ehcache</ artifactId >
< version >2.8.3</ version >
</ dependency >

第一步:首先配置ehcache.xml

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
<? xml version = "1.0" encoding = "UTF-8" ?>
< ehcache xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation = "ehcache.xsd"
          updateCheck = "true" monitoring = "autodetect"
          dynamicConfig = "true" >
 
    < diskStore path = "java.io.tmpdir" />   
    < defaultCache
             maxEntriesLocalHeap = "10000"
             eternal = "false"
             overflowToDisk = "false"
             timeToIdleSeconds = "120"
             timeToLiveSeconds = "120"
             diskSpoolBufferSizeMB = "30"
             maxEntriesLocalDisk = "10000000"
             diskExpiryThreadIntervalSeconds = "120"
             memoryStoreEvictionPolicy = "LRU" >
         < persistence strategy = "localTempSwap" />
     </ defaultCache >
 
     < cache name = "myCache"
            maxEntriesLocalHeap = "10000"
            maxEntriesLocalDisk = "1000"
            eternal = "false"
            diskSpoolBufferSizeMB = "30"
            timeToIdleSeconds = "300"
            timeToLiveSeconds = "600"
            memoryStoreEvictionPolicy = "LFU"
            transactionalMode = "off" >
         < persistence strategy = "localTempSwap" />
     </ cache >  
</ 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
2
3
4
5
6
7
8
9
10
11
<!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 -->
< cache:annotation-driven cache-manager = "ehcacheManager" />
 
<!-- cacheManager工厂类,指定ehcache.xml的位置 -->
< bean id = "ehcacheManagerFactory" class = "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
      < property name = "configLocation" value = "classpath:ehcache.xml" />
</ bean >
<!-- 声明cacheManager -->
< bean id = "ehcacheManager" class = "org.springframework.cache.ehcache.EhCacheCacheManager" >
      < property name = "cacheManager" ref = "ehcacheManagerFactory" />
</ bean >

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

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

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
package org.shop.entity;
 
import java.io.Serializable;
import java.util.Date;
 
public class SystemLog implements Serializable {
 
     private static final long serialVersionUID = -6579533328390250520L;
 
     private String id;
 
     private String description;
 
     private String method;
 
     private Long logType;
 
     private String requestIp;
 
     private String exceptioncode;
 
     private String exceptionDetail;
 
     private String params;
 
     private String createBy;
 
     private Date createDate;
 
     public String getId() {
         return id;
     }
 
     public void setId(String id) {
         this .id = id == null ? null : id.trim();
     }
 
     public String getDescription() {
         return description;
     }
 
     public void setDescription(String description) {
         this .description = description == null ? null : description.trim();
     }
 
     public String getMethod() {
         return method;
     }
 
     public void setMethod(String method) {
         this .method = method == null ? null : method.trim();
     }
 
     public Long getLogType() {
         return logType;
     }
 
     public void setLogType(Long logType) {
         this .logType = logType;
     }
 
     public String getRequestIp() {
         return requestIp;
     }
 
     public void setRequestIp(String requestIp) {
         this .requestIp = requestIp == null ? null : requestIp.trim();
     }
 
     public String getExceptioncode() {
         return exceptioncode;
     }
 
     public void setExceptioncode(String exceptioncode) {
         this .exceptioncode = exceptioncode == null ? null : exceptioncode.trim();
     }
 
     public String getExceptionDetail() {
         return exceptionDetail;
     }
 
     public void setExceptionDetail(String exceptionDetail) {
         this .exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim();
     }
 
     public String getParams() {
         return params;
     }
 
     public void setParams(String params) {
         this .params = params == null ? null : params.trim();
     }
 
     public String getCreateBy() {
         return createBy;
     }
 
     public void setCreateBy(String createBy) {
         this .createBy = createBy == null ? null : createBy.trim();
     }
 
     public Date getCreateDate() {
         return createDate;
     }
 
     public void setCreateDate(Date createDate) {
         this .createDate = createDate;
     }
}

第四步:编写dao,service

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

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

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
@Service ( "systemLogService" )
public class SystemLogServiceImpl implements SystemLogService {
 
     @Resource
     private SystemLogMapper systemLogMapper;
 
     @Override
     public int deleteSystemLog(String id) {       
               return systemLogMapper.deleteByPrimaryKey(id);
     }
 
     @Override
     //@CachePut(value="myCache")
     //@CacheEvict(value="myCache",allEntries=true,beforeInvocation=true)
     @CacheEvict (value= "myCache" ,key= "0" ,beforeInvocation= true )
     public int insert(SystemLog record) {       
               return systemLogMapper.insertSelective(record);
     }
 
     @Override
     @Cacheable (value= "myCache" ,key= "#id" )
     public SystemLog findSystemLog(String id) {       
              return systemLogMapper.selectByPrimaryKey(id);
     }
 
     @Override
     public int updateSystemLog(SystemLog record) {       
              return systemLogMapper.updateByPrimaryKeySelective(record);
     }
     @Override
     public int insertTest(SystemLog record) {       
            return systemLogMapper.insert(record);
     }
 
     @Override
     @Cacheable (value= "myCache" ,key= "0" )
     public int count() {
            int num = systemLogMapper.count();
            return num;
     }
 
}

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

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
@Controller
@RequestMapping ( "systemLogController" )
public class SystemLogController {
 
     @Resource
     private SystemLogService systemLogService;
 
     @RequestMapping ( "testLog" )
     public ModelAndView testLog(){   
         ModelMap modelMap = new ModelMap();
         SystemLog systemLog = systemLogService.findSystemLog( "c30e2398-079a-406b-a2f7-a85fa15ccac7" );
         modelMap.addAttribute( "data" , systemLog);
         return new ModelAndView( "index" ,modelMap);
     }
     @RequestMapping ( "insert" )
     @ResponseBody
     public boolean Insert(SystemLog record){
         systemLogService.insert(record);
         return true ;
     }
 
     @RequestMapping ( "test1" )
     public ModelAndView test1(){
         ModelMap modelMap = new ModelMap();
         int num =systemLogService.count();
         modelMap.addAttribute( "num" , num);
         return  new ModelAndView( "pageEhcache" ,modelMap);
     }
 
}

我们先测试查询的缓存,即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
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
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
< html >
   < head >
     < title >测试</ title
     < script type = "text/javascript" src="<%=request.getContextPath()%>/js/jquery-1.11.1.min.js"></ script >
     < script type = "text/javascript" >
        function insert(){
            var record = $("#formID").serializeArray();
            console.info(record);
            $.ajax({
                    url : "<%=request.getContextPath()%>/systemLogController/insert.do",
                    type : 'post',
                    async:true,
                    dataType:'json',
                    data : record,            
                    success:function(result){   
                        alert("插入成功!");
                    }
            });          
        }
     </ script >
   </ head
   < body >
   < h1 ><%=new Date()%></ h1 >
   < h1 >这是一个练习</ h1 >
      < form id = "formID" action = "" >
         id: < input name = "id" type = "text" />
         < input type = "button" value = "插入" onclick = "insert()" />
     </ form >
     
     总数:
     < h4 >${num}</ h4 >
   </ body >
</ 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级别的缓存效果性能可能会更好。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值