Netty游戏服务器实战开发(15):游戏服务器中的数据缓存

释放双眼,带上耳机,听听看~!

导读

游戏服务器缓存作用非常重要:很大部分决定游戏服务器性能问题。用好缓存能够一定程度上提高服务器性能和响应时间。给游戏带来流畅体验。

缓存的作用

在很多游戏服务器开发过程中,有需要提前加载到内存中的数据,有不需要加载到内存中的数据,当然,加载到内存中的数据可分为字典数据和部分玩家数据。比如:配表信息,玩家查询信息,玩家基础信息等。

通常我们使用redis作为一个缓存中间件,当然,redis不仅用于游戏服务器,也适用于很多传统互联网行业。是一款优秀的KV缓存数据库。性能还是得到很多开发者的认同。今天,我们在redis的基础上来封装一层缓存框架,使用到常用的游戏服务器当中。
Netty游戏服务器实战开发(15):游戏服务器中的数据缓存

有的设计方式其实通过另起一个进程,通过分配机器内存的形式来通过缓存。这种方式的优点就是可以扩展到不同的物理机器上面。易于维护。缺点就是必须得通过编写响应得程序来实现。但是对于一般得游戏开发团队来说无疑是一大压力。所以,很多都是利用开源的工具库。如图设计:
Netty游戏服务器实战开发(15):游戏服务器中的数据缓存

最流行的可能应该是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

给TA打赏
共{{data.count}}人
人已打赏
安全技术

Bootstrap 间隔 (Spacing)

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索