导读
游戏服务器缓存作用非常重要:很大部分决定游戏服务器性能问题。用好缓存能够一定程度上提高服务器性能和响应时间。给游戏带来流畅体验。
缓存的作用
在很多游戏服务器开发过程中,有需要提前加载到内存中的数据,有不需要加载到内存中的数据,当然,加载到内存中的数据可分为字典数据和部分玩家数据。比如:配表信息,玩家查询信息,玩家基础信息等。
通常我们使用redis作为一个缓存中间件,当然,redis不仅用于游戏服务器,也适用于很多传统互联网行业。是一款优秀的KV缓存数据库。性能还是得到很多开发者的认同。今天,我们在redis的基础上来封装一层缓存框架,使用到常用的游戏服务器当中。
有的设计方式其实通过另起一个进程,通过分配机器内存的形式来通过缓存。这种方式的优点就是可以扩展到不同的物理机器上面。易于维护。缺点就是必须得通过编写响应得程序来实现。但是对于一般得游戏开发团队来说无疑是一大压力。所以,很多都是利用开源的工具库。如图设计:
最流行的可能应该是redis这个内存NOSQL KV数据库了,应用层面非常广泛。而通常在游戏开发服务器后台来说,redis采用集群模式来提供缓存内存支持。redis天生的优化性能,能够支撑极高的IO和并发。因此,游戏中请求频繁的数据就可以保存到redis中。
使用场景:
-游戏活动信息
一般游戏中都有活动数据,一般有全服活动,单服活动等非常复杂的活动,通过游戏多元化,然而每一个玩家都会请求活动数据,因此,通常把活动相关的数据就会保存的redis中。
– 玩家基础数据
玩家信息来回读取,来回修改比较频繁。 读取频率较高,所以这类数据也适合保存到redis中。
使用场景其实很多,根据不同的业务,选不同的数据存储方式即可。下面我们采用redis模式,来实现一条高效方便的缓存框架工具。
实现方式
下面,通过代码的形式来实现一套缓存框架,基于redis的Java api实现我们系统中使用起来方便的模式。
第一步:通过定义公共接口的形式,来实现一个RedisInterface
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 1package com.twjitm.jump.logic.core.database.redis;
2
3import java.util.Map;
4
5/**
6 * @author twjitm - [Created on 2018-10-22 14:21]
7 */
8public interface RedisInterface {
9 /**
10 * 将所有的po对象的属性值放入到集合中
11 *
12 * @return
13 */
14 Map<String, String> getAllFeildsToHash();
15
16 /**
17 * 获取一个唯一键值
18 *
19 * @return
20 */
21 String getUniqueKey();
22
23 /**
24 * 获取属相列表长度
25 *
26 * @return
27 */
28 int getFieldLength();
29}
30
31
32
多个对象形式的接口:
1
2
3
4
5
6
7
8
9
10
11
12 1/**
2 * @author twjitm - [Created on 2018-10-22 14:27]
3 */
4public interface RedisListInterface extends RedisInterface {
5 /**
6 * 列表对象的子唯一主键属性数组(除去uid这个field之外的)
7 */
8 String[] getSubUniqueKey();
9}
10
11
12
定义来三个方法,一个是获取全部字段表,一个获取唯一主键表,一个是获取属性字段的个数。子接口中有获取子对象的唯一键。
定义这几根方法有啥用呢?我们下面来看一个实际例子:在此之前,先介绍一下个工具类,也就是反射相关的东西,要连反射不知道的可以先看看相关的知识,在这就不细说连,工具通过反射获取一个实体类的属性字段并赋值,通过反射将字符串对象转化为实体对象的一个过程。
工具类源码:
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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 1package com.twjitm.jump.common.utils.zutils;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.InputStreamReader;
7import java.lang.reflect.Field;
8import java.lang.reflect.Method;
9import java.net.MalformedURLException;
10import java.net.URL;
11import java.util.Date;
12import java.util.HashMap;
13import java.util.List;
14import java.util.Map;
15import java.util.regex.Matcher;
16import java.util.regex.Pattern;
17
18
19/**
20 * @author twjitm
21 */
22public class ZCollectionUtil {
23
24 /**
25 * 截取某列表的部分数据
26 *
27 * @param <T>
28 * @param list
29 * @param skip
30 * @param pageSize
31 */
32 public static <T> List<T> getSubListPage(List<T> list, int skip, int pageSize) {
33 if (list == null || list.isEmpty()) {
34 return null;
35 }
36 int startIndex = skip;
37 int endIndex = skip + pageSize;
38 if (startIndex > endIndex || startIndex > list.size()) {
39 return null;
40 }
41 if (endIndex > list.size()) {
42 endIndex = list.size();
43 }
44 return list.subList(startIndex, endIndex);
45 }
46
47 /**
48 * 通过远程URL获取本地IP地址
49 *
50 * @param urlCanGainIp
51 */
52 public static String getInetIpAddress(String urlCanGainIp) {
53 InputStream in = null;
54 try {
55 URL url = new URL(urlCanGainIp);
56 in = url.openStream();
57 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
58 String line = "", ip = null;
59 while ((line = reader.readLine()) != null) {
60 ip = parseIpAddress(line);
61 if (!ZStringUtil.isEmptyStr(ip)) {
62 return ip;
63 }
64 }
65 } catch (MalformedURLException e) {
66 e.printStackTrace();
67 } catch (IOException e) {
68 e.printStackTrace();
69 } finally {
70 if (in != null) {
71 try {
72 in.close();
73 } catch (IOException e) {
74 e.printStackTrace();
75 }
76 }
77 }
78 return null;
79 }
80
81 /**
82 * 判断某个地址是否是IP地址
83 *
84 * @param content
85 */
86 public static boolean isIpAddress(String content) {
87 String rt = parseIpAddress(content);
88 if (!ZStringUtil.isEmptyStr(rt)) {
89 if (rt.equals(content)) {
90 return true;
91 }
92 }
93 return false;
94 }
95
96 /*
97 * 解释IP地址
98 */
99 private static String parseIpAddress(String content) {
100 String regexIp = "((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|[1-9])";
101 Pattern pattern = Pattern.compile(regexIp);
102 Matcher matcher = pattern.matcher(content);
103 String rt = null;
104 while (matcher.find()) {
105 rt = matcher.group();
106 }
107 return rt;
108 }
109
110 /**
111 * 获取某个对象某些字段的Map
112 *
113 * @param obj
114 */
115 public static Map<String, String> getMap(Object obj, String... strings) {
116 Map<String, String> map = new HashMap<String, String>();
117 boolean addAllFields = false;
118 if (strings == null || strings.length == 0) {
119 addAllFields = true;
120 }
121 if (obj != null) {
122 Field[] fields = getAllFields(obj);
123 for (Field field : fields) {
124 field.setAccessible(true);
125 try {
126 boolean needsAddToMap = false;
127 for (String s : strings) {
128 if (field.getName().equals(s)) {
129 needsAddToMap = true;
130 break;
131 }
132 }
133 if (needsAddToMap || addAllFields) {
134 map.put(field.getName(), getFieldsValueStr(obj, field.getName()));
135 }
136 } catch (Exception e) {
137 e.printStackTrace();
138 }
139 }
140 }
141 if (!addAllFields && strings.length != map.size()) {
142 return new HashMap<>(16);
143 }
144 return map;
145 }
146
147 private static Field[] getAllFields(Object obj) {
148 Class<?> clazz = obj.getClass();
149 Field[] rt = null;
150 for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
151 Field[] tmp = clazz.getDeclaredFields();
152 rt = combine(rt, tmp);
153 }
154 return rt;
155 }
156
157 private static Field[] combine(Field[] a, Field[] b) {
158 if (a == null) {
159 return b;
160 }
161 if (b == null) {
162 return a;
163 }
164 Field[] rt = new Field[a.length + b.length];
165 System.arraycopy(a, 0, rt, 0, a.length);
166 System.arraycopy(b, 0, rt, a.length, b.length);
167 return rt;
168 }
169
170 private static Object getFieldsValueObj(Object obj, String fieldName) {
171 Field field = getDeclaredField(obj, fieldName);
172 field.setAccessible(true);
173 try {
174 return field.get(obj);
175 } catch (Exception e) {
176 e.printStackTrace();
177 }
178 return null;
179 }
180
181 private static String getFieldsValueStr(Object obj, String fieldName) {
182 Object o = ZCollectionUtil.getFieldsValueObj(obj, fieldName);
183 if (o instanceof Date) {
184 return ZDateUtil.dateToString((Date) o);
185 }
186 if (o == null) {
187 return null;
188 }
189 return o.toString();
190 }
191
192 private static Field getDeclaredField(Object object, String fieldName) {
193 Class<?> clazz = object.getClass();
194 for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
195 try {
196 return clazz.getDeclaredField(fieldName);
197 } catch (Exception e) {
198 }
199 }
200 return null;
201 }
202
203 private static Method getSetMethod(Object object, String method, Class<?> fieldType) {
204 Class<?> clazz = object.getClass();
205 for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
206 try {
207 return clazz.getDeclaredMethod(method, fieldType);
208 } catch (Exception e) {
209 }
210 }
211 return null;
212 }
213
214 /**
215 * map集合里反序列化对象
216 *
217 * @param map map数据字段
218 * @param obj 对象
219 * @param <T>
220 * @return
221 */
222 public static <T> T getObjFromMap(Map<String, String> map, Object obj) {
223 try {
224 for (String key : map.keySet()) {
225 Field field = getDeclaredField(obj, key);
226 Method method = getSetMethod(obj, buildSetMethod(key), field.getType());
227 if (field.getType() == Integer.class || field.getType() == int.class) {
228 method.invoke(obj, Integer.parseInt(map.get(key)));
229 } else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
230 method.invoke(obj, Boolean.parseBoolean(map.get(key)));
231 } else if (field.getType() == Long.class || field.getType() == long.class) {
232 method.invoke(obj, Long.parseLong(map.get(key)));
233 } else if (field.getType() == Float.class || field.getType() == float.class) {
234 method.invoke(obj, Float.parseFloat(map.get(key)));
235 } else if (field.getType() == Double.class || field.getType() == double.class) {
236 method.invoke(obj, Double.parseDouble(map.get(key)));
237 } else if (field.getType() == Byte.class || field.getType() == byte.class) {
238 method.invoke(obj, Byte.parseByte(map.get(key)));
239 } else if (field.getType() == Short.class || field.getType() == short.class) {
240 method.invoke(obj, Short.parseShort(map.get(key)));
241 } else if (field.getType() == String.class) {
242 method.invoke(obj, map.get(key));
243 } else if (field.getType() == Date.class) {
244 method.invoke(obj, ZDateUtil.stringToDate(map.get(key)));
245 }
246 }
247 return (T) obj;
248 } catch (Exception e) {
249 e.printStackTrace();
250 }
251 return null;
252 }
253
254 /**
255 * 从map里构造出一个实例对象
256 *
257 * @param map
258 * @param clazz
259 * @return
260 */
261 public static <T> T getObjFromMap(Map<String, String> map, Class<?> clazz) {
262 try {
263 Object obj = clazz.newInstance();
264 return getObjFromMap(map, obj);
265 } catch (Exception e) {
266 e.printStackTrace();
267 }
268 return null;
269 }
270
271 private static String buildSetMethod(String fieldName) {
272 StringBuffer sb = new StringBuffer("set");
273 if (fieldName.length() > 1) {
274 String first = fieldName.substring(0, 1);
275 String next = fieldName.substring(1);
276 sb.append(first.toUpperCase()).append(next);
277 } else {
278 sb.append(fieldName.toUpperCase());
279 }
280 return sb.toString();
281 }
282
283 /**
284 * 判断某个list是否没有数据
285 *
286 * @param <T>
287 * @param list
288 * @return
289 */
290 public static <T> boolean isEmpty(List<T> list) {
291 boolean b = false;
292 if (list == null || list.isEmpty()) {
293 b = true;
294 }
295 return b;
296 }
297
298 /**
299 * 判断一个map是否为空
300 *
301 * @param map
302 * @param <T>
303 * @return
304 */
305 public static boolean isEmpty(Map<Object, Object> map) {
306 boolean b = false;
307 if (map == null || map.isEmpty()) {
308 b = true;
309 }
310 return b;
311 }
312
313 /**
314 * 反射获取某个类的熟悉名称集合
315 *
316 * @param obj
317 * @return
318 */
319 public static Map<String, String> getAllFeildsToHash(Object obj) {
320 Map<String, String> map = new HashMap<>();
321 if (obj != null) {
322 Field[] fields = getAllFields(obj);
323 for (Field field : fields) {
324 field.setAccessible(true);
325 map.put(field.getName(), getFieldsValueStr(obj, field.getName()));
326 }
327 }
328 return map;
329 }
330}
331
332
333
回到主题,我们实现一个需要缓存到对象类,例如Item 玩家的道具这种东西。
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 1package com.twjitm.jump.logic.game.item.entity;
2
3import com.twjitm.jump.common.utils.zutils.ZCollectionUtil;
4import com.twjitm.jump.logic.core.database.redis.RedisListInterface;
5
6import java.util.Map;
7
8/**
9 * @author twjitm - [Created on 2018-10-24 18:08]
10 */
11public class ItemPo implements RedisListInterface {
12 public ItemPo(){
13
14 }
15 /**
16 * playerId
17 */
18 private long playerId;
19 /**
20 *
21 */
22 private long id;
23 /**
24 * item id
25 */
26 private int sdId;
27 /**
28 * 类型
29 */
30 private int type;
31 /**
32 * 品质
33 */
34 private int quality;
35 /**
36 * 等级
37 */
38 private int level;
39 /**
40 * 数量
41 */
42 private int count;
43
44 public ItemPo(long playerId, int id, int sdId, int type, int quality, int level, int count) {
45 this.playerId = playerId;
46 this.id = id;
47 this.sdId = sdId;
48 this.type = type;
49 this.quality = quality;
50 this.level = level;
51 this.count = count;
52 }
53
54 public long getPlayerId() {
55 return playerId;
56 }
57
58 public void setPlayerId(long playerId) {
59 this.playerId = playerId;
60 }
61
62 public int getSdId() {
63 return sdId;
64 }
65
66 public void setSdId(int sdId) {
67 this.sdId = sdId;
68 }
69
70 public int getType() {
71 return type;
72 }
73
74 public void setType(int type) {
75 this.type = type;
76 }
77
78 public int getQuality() {
79 return quality;
80 }
81
82 public void setQuality(int quality) {
83 this.quality = quality;
84 }
85
86 public int getLevel() {
87 return level;
88 }
89
90 public void setLevel(int level) {
91 this.level = level;
92 }
93
94 public int getCount() {
95 return count;
96 }
97
98 public void setCount(int count) {
99 this.count = count;
100 }
101
102 public long getId() {
103 return id;
104 }
105
106 public void setId(long id) {
107 this.id = id;
108 }
109
110 @Override
111 public String[] getSubUniqueKey() {
112 return new String[]{"id", "sdId"};
113 }
114
115 @Override
116 public Map<String, String> getAllFeildsToHash() {
117 return ZCollectionUtil.getAllFeildsToHash(this);
118 }
119
120 @Override
121 public String getUniqueKey() {
122 return "playerId";
123 }
124
125 @Override
126 public int getFieldLength() {
127 return 0;
128 }
129}
130
131
132
实现前面提到的RedisListInterface接口中定义的方法。例如使用playerid来作为标示字段,利用id和sdid组合来标示一条一条数据的唯一表示。
在redis提供的Java api接口文档中。我们进行扩方法:
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 1
2 /**
3 * 通过反射从缓存里获取一个对象 缺省默认时间,默认的key是有uid这个字段拼接而成
4 *
5 * @param <T>
6 * @param key
7 * @param clazz
8 * @return
9 */
10 @SuppressWarnings("unchecked")
11 public <T> T getObjectFromHash(String key, Class<?> clazz) {
12 return (T) getObjectFromHash(key, clazz, RedisKey.NORMAL_LIFECYCLE);
13 }
14
15 /**
16 * 通过反射从缓存里获取一个对象 缺省默认时间
17 *
18 * @param <T>
19 * @param key
20 * @param clazz
21 * @return
22 */
23
24 @SuppressWarnings("unchecked")
25 public <T> T getObjectFromHash(String key, Class<?> clazz, String uniqueKey) {
26 return (T) getObjectFromHash(key, clazz, uniqueKey, RedisKey.NORMAL_LIFECYCLE);
27 }
28
29 /*
30 * 通过反射从缓存里获取一个对象,默认的key是有uid这个字段拼接而成
31 * @param key
32 * @param clazz
33 * @return
34 */
35 @SuppressWarnings("unchecked")
36 public <T> T getObjectFromHash(String key, Class<?> clazz, int second) {
37 return (T) getObjectFromHash(key, clazz, "uid", second);
38 }
39
40 /*
41 * 通过反射从缓存里获取一个对象
42 * @param key
43 * @param clazz
44 * @param uniqueKey 此key由哪个字段拼接而成的
45 * @return
46 */
47 @SuppressWarnings("unchecked")
48 public <T> T getObjectFromHash(String key, Class<?> clazz, String uniqueKey, int seconds) {
49 Jedis jedis = null;
50 boolean sucess = true;
51 try {
52 jedis = jedisPool.getResource();
53 //Transaction t = jedis.multi();
54 //Response<Map<String,String>> respMap=t.hgetAll(key);
55 //t.expire(key, seconds);
56 //t.exec();
57 //Map<String, String> map = respMap.get();
58 Map<String, String> map = jedis.hgetAll(key);
59 if (map.size() > 0) {
60 Object obj = clazz.newInstance();
61 if (obj instanceof RedisInterface && !(obj instanceof RedisListInterface)) {
62 if (map.size() != ((RedisInterface) obj).getFieldLength()) {
63 logger.info("+-+ redis getObjectFromHash:" + clazz.getName() + " expire.hash list size is more than expact. map:" + JSON.toJSONString(map));
64 jedis.expire(key, 0);
65 return null;
66 }
67 }
68 map.put(uniqueKey, key.split("#")[1]);
69 if (seconds >= 0) {
70 jedis.expire(key, seconds);
71 }
72 return (T) ZCollectionUtil.getObjFromMap(map, obj);
73 }
74 } catch (Exception e) {
75 sucess = false;
76 returnBrokenResource(jedis, "getObjectFromHash:" + key, e);
77 } finally {
78 if (sucess && jedis != null) {
79 returnResource(jedis);
80 }
81 }
82 return null;
83 }
84
85 /*
86 * 通过反射从缓存里获取一个对象
87 * 如果redis map少参数 返回默认值
88 * @param key
89 * @param clazz
90 * @param uniqueKey 此key由哪个字段拼接而成的
91 * @return
92 */
93 @SuppressWarnings("unchecked")
94 public <T> T getObjectFromHashWithTrue(String key, Class<?> clazz, String uniqueKey, int seconds) {
95 Jedis jedis = null;
96 boolean sucess = true;
97 try {
98 jedis = jedisPool.getResource();
99 Map<String, String> map = jedis.hgetAll(key);
100 if (map.size() > 0) {
101 Object obj = clazz.newInstance();
102 map.put(uniqueKey, key.split("#")[1]);
103 if (seconds >= 0) {
104 jedis.expire(key, seconds);
105 }
106 return (T) ZCollectionUtil.getObjFromMap(map, obj);
107 }
108 } catch (Exception e) {
109 sucess = false;
110 returnBrokenResource(jedis, "getObjectFromHash:" + key, e);
111 } finally {
112 if (sucess && jedis != null) {
113 returnResource(jedis);
114 }
115 }
116 return null;
117 }
118
119 /**
120 * 将一个列表对象放入缓存
121 *
122 * @param key
123 * @param list
124 */
125
126 public void setListToHash(String key, List<? extends RedisListInterface> list) {
127 setListToHash(key, list, RedisKey.NORMAL_LIFECYCLE);
128 }
129
130 /*
131 * 将一个列表对象放入缓存,并设置有效期
132 * @param key
133 * @param list
134 * @param seconds
135 */
136 public boolean setListToHash(String key, List<? extends RedisListInterface> list, int seconds) {
137 Jedis jedis = null;
138 boolean sucess = true;
139 try {
140 //Transaction t = jedis.multi();
141 Map<String, String> map = new HashMap<String, String>();
142 Map<String, String> keyMap = null;
143 String[] keyNames = null;
144 for (RedisListInterface po : list) {
145 keyNames = po.getSubUniqueKey();
146 keyMap = ZCollectionUtil.getMap(po, keyNames);
147 StringBuilder sb = new StringBuilder();
148 for (String keyName : keyNames) {
149 sb.append(keyMap.get(keyName)).append("#");
150 }
151 map.put(sb.toString(), GameUtil.getJsonStr(po.getAllFeildsToHash()));
152 }
153 //t.hmset(key, map);
154 //t.expire(key, seconds);
155 //t.exec();
156 jedis = jedisPool.getResource();
157 jedis.hmset(key, map);
158 if (seconds >= 0) {
159 jedis.expire(key, seconds);
160 }
161 } catch (Exception e) {
162 sucess = false;
163 returnBrokenResource(jedis, "setListToHash:" + key, e);
164 } finally {
165 if (sucess && jedis != null) {
166 returnResource(jedis);
167 }
168 }
169 return sucess;
170 }
171
172 /**
173 * 从缓存里还原一个列表对象
174 *
175 * @param key
176 * @param clazz
177 * @return
178 */
179 @SuppressWarnings("unchecked")
180
181 public <T> List<T> getListFromHash(String key, Class<?> clazz, int seconds) {
182 Jedis jedis = null;
183 boolean sucess = true;
184 Map<String, String> map = null;
185 try {
186 jedis = jedisPool.getResource();
187 map = jedis.hgetAll(key);
188 if (map != null && map.size() > 0) {
189 List<T> rt = new ArrayList<T>();
190 RedisListInterface po = null;
191 Map<String, String> mapFields = null;
192 String keyNames[] = null;
193 for (Entry<String, String> entry : map.entrySet()) {
194 String fieldKey = entry.getKey();
195 mapFields = GameUtil.getMapFromJson(entry.getValue());
196 po = (RedisListInterface) clazz.newInstance();
197 mapFields.put(po.getUniqueKey(), key.split("#")[1]);
198 keyNames = po.getSubUniqueKey();
199 String uniqueKeys[] = fieldKey.split("#");
200 for (int i = 0, j = keyNames.length; i < j; i++) {
201 mapFields.put(keyNames[i], uniqueKeys[i]);
202 }
203 ZCollectionUtil.getObjFromMap(mapFields, po);
204 rt.add((T) po);
205 }
206 if (seconds >= 0) {
207 jedis.expire(key, seconds);
208 }
209 return rt;
210 }
211 } catch (Exception e) {
212 sucess = false;
213 returnBrokenResource(jedis, "getListFromHash:" + key, e);
214 } finally {
215 if (sucess && jedis != null) {
216 returnResource(jedis);
217 }
218 }
219 return null;
220 }
221
222 /**
223 * 从缓存里还原一个列表对象
224 *
225 * @param key
226 * @param clazz
227 * @return
228 */
229 @SuppressWarnings("unchecked")
230
231 public <T> T getObjectFromList(String key, String subUnionkey, Class<?> clazz, int seconds) {
232 Jedis jedis = null;
233 boolean sucess = true;
234 Map<String, String> map = null;
235 try {
236 jedis = jedisPool.getResource();
237 String value = jedis.hget(key, subUnionkey);
238 if (ZStringUtil.isEmptyStr(value)) {
239 return null;
240 }
241 Map<String, String> mapFields = GameUtil.getMapFromJson(value);
242 RedisListInterface po = (RedisListInterface) clazz.newInstance();
243 mapFields.put(po.getUniqueKey(), key.split("#")[1]);
244 String[] keyNames = po.getSubUniqueKey();
245 String uniqueKeys[] = subUnionkey.split("#");
246 for (int i = 0, j = keyNames.length; i < j; i++) {
247 mapFields.put(keyNames[i], uniqueKeys[i]);
248 }
249 ZCollectionUtil.getObjFromMap(mapFields, po);
250 if (seconds >= 0) {
251 jedis.expire(key, seconds);
252 }
253 return (T) po;
254 } catch (Exception e) {
255 sucess = false;
256 returnBrokenResource(jedis, "getListFromHash:" + key, e);
257 } finally {
258 if (sucess && jedis != null) {
259 returnResource(jedis);
260 }
261 }
262 return null;
263 }
264
265 /**
266 * 批量删除对象
267 *
268 * @param key
269 * @param list
270 */
271
272 public boolean deleteList(String key, List<? extends RedisListInterface> list) {
273 Jedis jedis = null;
274 boolean sucess = true;
275 try {
276 String keys[] = new String[list.size()];
277 String keyNames[] = null;
278 Map<String, String> keyMap = null;
279 int index = 0;
280 for (RedisListInterface po : list) {
281 keyNames = po.getSubUniqueKey();
282 keyMap = ZCollectionUtil.getMap(po, keyNames);
283 StringBuilder sb = new StringBuilder();
284 for (String keyName : keyNames) {
285 sb.append(keyMap.get(keyName)).append("#");
286 }
287 keys[index++] = sb.toString();
288 }
289 jedis = jedisPool.getResource();
290 jedis.hdel(key, keys);
291 } catch (Exception e) {
292 sucess = false;
293 returnBrokenResource(jedis, "deleteList:" + key, e);
294 } finally {
295 if (sucess && jedis != null) {
296 returnResource(jedis);
297 }
298 }
299 return sucess;
300 }
301
302
303
最后我们使用这些方法就能够对我们定义的对象进行存储和修改了。
源码可参考 https://github.com/twjitm/twjitm-core