spring aop + xmemcached 配置service层缓存策略

简介:


本文转自 bxst 51CTO博客,原文链接:http://blog.51cto.com/13013670/1944035

Memcached 作用与使用 基本介绍

1,对于缓存的存取方式,简言之,就是以键值对的形式将数据保存在内存中。在日常业务中涉及的操作无非就是增删改查。加入缓存机制后,查询的时候,对数据进行缓存,增删改的时候,清除缓存即可。这其中对于缓存的闭合就非常重要,如果缓存没有及时得到更新,那用户就会获取到过期数据,就会产生问题。

2,对于单一业务的缓存管理(数据库中只操作单表),只需生成一个key,查询时,使用key,置入缓存;增删改时,使用key,清除缓存。将key与表绑定,操作相对简单。

3,但是在现实业务中,更多的是对关联表的增删改查(数据库多表操作),业务之间互相关联,数据库中的某张表不止一个业务再进行操作,将缓存拦截在service层,对业务进行缓存,对多表进行缓存。

4,业务层缓存实现策略:

  4.1,在缓存中建立一个key为"union_query",value为“hashmap<prefix,uqversion>(‘简称uqmap’)“的缓存,prefix保存的是当前业务操作涉及到的数据库表名的组合(数据库表名的唯一性),使用‘|’分隔(例 prefix=“A|B”,此次业务将操作A表与B表),uqversion是业务版本号,从0开始递增。

  4.2,调用一个查询业务时,对数据进行缓存,设置operation为1,告诉cache对象,这是一个缓存操作,例如调用 queryAB(args[])方法时,cache对象切入,将prefix(即”A|B“)与uqversion(初始化为0),存入uqmap中进行缓存。

  4.3,将prefix,uqversion,方法明+参数,进行拼接,使用md5进行加密后作为一个key,将方法的结果集作为value,进行缓存。至此缓存成功。

  4.4,当第二个请求来调用queryAB时,cache对象切入,首先,查询uqmap对象,使用prefix找到对应的uqversion,然后,通过拼接加密获取key,最后取得结果集进行返回。

  4.5,当有一个updateA方法被调用时,设置operation为4,告诉cache对象,这是一个删除缓存的操作,此时prefix的值为“A”,cache对象切入,获取全局的uqmap,遍历其中的prefix,是否包含了表A的名称:如果包含,则更新此prefix的uqversion进行自增,uqversion一旦发生变化,4.3中组合的key将不复存在,业务缓存也就消失了。(对于复杂的updateAB方法,遍历prefix要复杂一点,可以实现)

  4.6,当第三个请求来调用queryAB时,可以获取到uqversion,组合成key后,但是没有对应的value。此时确定缓存不存在时,继续正常执行方法,获取结果集,返回给客户的同时,将结果集进行缓存。

5,对于缓存的操作,网上有三种api可以选择(memcached client forjava、spymemcached、xmemcached),具体的好坏,本人在这就不做分析。本人使用的是XMemcached api。

具体实现细节:

1,新建 @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类。定义缓存策略。

?
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
import  java.lang.annotation.Documented;
import  java.lang.annotation.ElementType;
import  java.lang.annotation.Inherited;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;
 
/**
  * 用于查找的时候,放置缓存信息
  * @author shufeng
  */
@Target (ElementType.METHOD)
@Retention (RetentionPolicy.RUNTIME)
@Documented
@Inherited
public  @interface  XmemCache{
 
     /**
      * 值为当前操作的表名,表名唯一
      * 涉及到多表操作,使用|分隔
      */
     String prefix()  default  "" ;
     
     /*
      *    缓存有效期 设置,单位为秒
      *    指定间隔时间,默认值为3600秒(1小时)
      * */
     int interval() default 3600; 
     
     /**
      *     1 从cache里取值,如果未置入cache,则置入
      *   2 replace cache value                     未扩展
      *   3 replace cache value,并返回旧值         未扩展
      *   4 remove cache key 从cache里删除对应的缓存        
      *   5 remove cache key 从cache里删除对应的缓存,并返回未删除之前的值       未扩展
      **/
     int  operation()  default  1
}

2,memcache基础操作类,对一些常用方法进行封装,对memcachedclient进行配置

?
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
import  java.io.IOException;
import  java.io.InputStream;
import  java.util.HashMap;
import  java.util.Iterator;
import  java.util.Map;
import  java.util.Properties;
import  java.util.Set;
import  java.util.concurrent.TimeoutException;
 
import  org.slf4j.Logger;
import  org.slf4j.LoggerFactory;
import  org.springframework.beans.factory.DisposableBean;
 
import  com.node.hlhw.rbac.api.constant.Constant;
 
import  net.rubyeye.xmemcached.GetsResponse;
import  net.rubyeye.xmemcached.MemcachedClient;
import  net.rubyeye.xmemcached.MemcachedClientBuilder;
import  net.rubyeye.xmemcached.XMemcachedClientBuilder;
import  net.rubyeye.xmemcached.command.BinaryCommandFactory;
import  net.rubyeye.xmemcached.exception.MemcachedException;
import  net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
import  net.rubyeye.xmemcached.transcoders.SerializingTranscoder;
import  net.rubyeye.xmemcached.utils.AddrUtil;
 
/**
  * @author Melody shufeng
  * 对memcachedclient进行封装,添加一下常用方法
  */
public  class  MemcachedOperate  implements  DisposableBean {
 
     /*
      * timeout - Operation timeout,if the method is not returned in this
      * time,throw TimeoutException timeout - operation timeout,in milliseconds
      * exp - An expiration time, in seconds. Can be up to 30 days. After 30
      * days, is treated as a unix timestamp of an exact date. value - stored
      * data
      */
     private static final Logger logger = LoggerFactory.getLogger(MemcachedOperate.class);
     
     private static Properties PROPERTIES = new Properties();
     
     private static String MEMCACHED_SETTING = "memcached.properties";
     
     private static MemcachedClient memcachedClient;
     
 
     public static MemcachedClient getClient(){
         return memcachedClient;
     }
     
     
     /**
      * 静态代码块,类加载时,初始化缓存客户端
      * 确保只创建一个client实例
      * author shufeng 
      */
     static {
         InputStream in = Object.class.getResourceAsStream("/" + MEMCACHED_SETTING);
         try {
             PROPERTIES.load(in);
         } catch (IOException e) {
             e.printStackTrace();
         }
         String servers = PROPERTIES.getProperty("memcached.servers", "");
         if (null != servers && !"".equals(servers)) {
             try {
                 logger.debug("启动memcached连接");
                 MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(servers));
                 builder.setConnectionPoolSize(100);
                 builder.setFailureMode(true);
                 builder.setCommandFactory(new BinaryCommandFactory());
                 builder.setSessionLocator(new KetamaMemcachedSessionLocator());
                 builder.setTranscoder(new SerializingTranscoder());
                 memcachedClient = builder.build();
                 memcachedClient.setEnableHeartBeat(false); // 关闭心跳
                 memcachedClient.flushAll(); // 清空缓存
             } catch (IOException e) {
                 e.printStackTrace();
             } catch (TimeoutException e) {
                 e.printStackTrace();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } catch (MemcachedException e) {
                 e.printStackTrace();
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
     }
     
     /**
      * @param key
      * @return 获取value
      */
     public static Object get(String key) {
         Object object = null;
         try {
             object = memcachedClient.get(key);
         } catch (TimeoutException e) {
             e.printStackTrace();
         } catch (InterruptedException e) {
             e.printStackTrace();
         } catch (MemcachedException e) {
             e.printStackTrace();
         }
         return object;
     }
 
 
     public static void setWithNoReply(String key, int exp, Object value) {
         try {
             memcachedClient.setWithNoReply(key, exp, value);
         } catch (InterruptedException e) {
             e.printStackTrace();
相关文章
|
20天前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
116 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
8天前
|
前端开发 Java Spring
关于spring mvc 的 addPathPatterns 拦截配置常见问题
关于spring mvc 的 addPathPatterns 拦截配置常见问题
|
9天前
|
机器学习/深度学习 缓存 NoSQL
深度学习在图像识别中的应用与挑战后端开发中的数据缓存策略
本文深入探讨了深度学习技术在图像识别领域的应用,包括卷积神经网络(CNN)的原理、常见模型如ResNet和VGG的介绍,以及这些模型在实际应用中的表现。同时,文章也讨论了数据增强、模型集成等改进性能的方法,并指出了当前面临的计算资源需求高、数据隐私等挑战。通过综合分析,本文旨在为深度学习在图像识别中的进一步研究和应用提供参考。 本文探讨了后端开发中数据缓存的重要性和实现方法,通过具体案例解析Redis在实际应用中的使用。首先介绍了缓存的基本概念及其在后端系统性能优化中的作用;接着详细讲解了Redis的常见数据类型和应用场景;最后通过一个实际项目展示了如何在Django框架中集成Redis,
|
9天前
|
缓存 监控 负载均衡
在使用CDN时,如何配置缓存规则以优化性能
在使用CDN时,如何配置缓存规则以优化性能
|
21天前
|
缓存 JavaScript 中间件
优化Express.js应用程序性能:缓存策略、请求压缩和路由匹配
在开发Express.js应用时,采用合理的缓存策略、请求压缩及优化路由匹配可大幅提升性能。本文介绍如何利用`express.static`实现缓存、`compression`中间件压缩响应数据,并通过精确匹配、模块化路由及参数化路由提高路由处理效率,从而打造高效应用。
61 6
消息中间件 缓存 监控
81 0
|
21天前
|
Java 数据库连接 Maven
Spring基础1——Spring(配置开发版),IOC和DI
spring介绍、入门案例、控制反转IOC、IOC容器、Bean、依赖注入DI
Spring基础1——Spring(配置开发版),IOC和DI
|
1月前
|
缓存 NoSQL Java
揭秘性能提升的超级武器:掌握Hibernate二级缓存策略!
【9月更文挑战第3天】在软件开发中,性能优化至关重要。使用Hibernate进行数据持久化的应用可通过二级缓存提升数据访问速度。一级缓存随Session生命周期变化,而二级缓存是SessionFactory级别的全局缓存,能显著减少数据库访问次数,提高性能。要启用二级缓存,需在映射文件或实体类上添加相应配置。然而,并非所有场景都适合使用二级缓存,需根据业务需求和数据变更频率决定。此外,还可与EhCache、Redis等第三方缓存集成,进一步增强缓存效果。合理运用二级缓存策略,有助于大幅提升应用性能。
53 5
|
1月前
|
存储 缓存 前端开发
缓存技术在软件开发中的应用与优化策略
缓存技术在软件开发中的应用与优化策略
|
存储 Java Spring
原来使用 Spring 实现策略模式可以这么简单!
Hello,大家好,我是鸭血粉丝~ 最近看同事的代码时候,学到了个小技巧,在某些场景下非常挺有用的,这里分享一下给大家。
原来使用 Spring 实现策略模式可以这么简单!
下一篇
无影云桌面