KVStore的简单介绍
阿里云KVStore兼容Redis。因为KVStore就相当于Redis的服务器端,我们代码只是当作客户端,链接上服务器端就行了,阿里云的KVStore详情文档见,https://docs.aliyun.com/#/pub/kvstore/key-value-store/kvstore-introduction。
C#客户端链接OCS
1.阿里云文档上介绍的是用ServiceStack去链接KVStore。那我们项目中就用nuget去下载ServiceStack包。nuget搜索ServiceStack,搜索到的结果如下图,安装图中标识的就可以了。这个应该是最新的V4版本,当提醒你需要用商业版的时候,可以去还原之前的V3版本,具体还原方法见,https://github.com/ServiceStackV3/ServiceStackV3。
nuget搜索结果如下:
2.安装好以后,写链接和调用kvstore的代码。其中_setting.AccessId, _setting.AccessKey, _setting.HostAddress,分别是KVStore的实例ID,链接密码和链接地址。
1 using ServiceStack.Redis;
2 //using ServiceStack.Text;
3 using ServiceStack.Common;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using System.Web.Script.Serialization;
10 using Zupo.Core.Caching;
11 using System.Text.RegularExpressions;
12
13
14 namespace KVStore
15 {
16 public class KVStoreService
17 {
18
19 IKVStoreSetting _setting;
20 private IRedisClient redisClient;
21 private bool linkServer = true;
22
23 public KVStoreService(IKVStoreSetting setting)
24 {
25 try
26 {
27 this._setting = setting;
28 //连接池模式
29 //string[] testReadWriteHosts = new[] {
30 //string.Format("redis://:{0}:{1}@{2}:6379",_setting.AccessId,_setting.AccessKey,_setting.HostAddress)/*redis://:实例id:密码@访问地址:端口*/
31 //};
32 //RedisClientManagerConfig RedisConfig = new RedisClientManagerConfig();
33 //RedisConfig.AutoStart = true;
34 //RedisConfig.MaxReadPoolSize = 60;
35 //RedisConfig.MaxWritePoolSize = 60;
36 ////RedisConfig.VerifyMasterConnections = false;//需要设置
37 ////PooledRedisClientManager redisPoolManager = new PooledRedisClientManager(10/*连接池个数*/, 10/*连接池超时时间*/, testReadWriteHosts);
38 //PooledRedisClientManager redisPoolManager = new PooledRedisClientManager(10/*连接池个数*/, 10/*连接池超时时间*/, testReadWriteHosts);
39 //redisClient = redisPoolManager.GetClient();//获取连接
40 ////RedisNativeClient redisNativeClient = (RedisNativeClient)redisClient;
41 ////redisNativeClient.Client = null;//KVStore不支持client setname所以这里需要显示的把client对象置为null
42 //var dbSize = redisClient.DbSize;
43
44 //单链接模式
45 //string host = _setting.HostAddress;/*访问host地址*/
46 //string password = string.Format("{0}:{1}", _setting.AccessId, _setting.AccessKey);/*实例id:密码*/
47 //redisClient = new RedisClient(host, 6379, password);
48 //var dbSize = redisClient.DbSize;
49
50 RedisClientManagerConfig RedisConfig = new RedisClientManagerConfig();
51 RedisConfig.AutoStart = true;
52 RedisConfig.MaxReadPoolSize = 60;
53 RedisConfig.MaxWritePoolSize = 60;
54 RedisConfig.DefaultDb = 1; //默认第一个db
55
56 PooledRedisClientManager prcm = new PooledRedisClientManager(new List<string>() { string.Format("{0}:{1}@{2}:6379", _setting.AccessId, _setting.AccessKey, _setting.HostAddress) },
57 new List<string>() { string.Format("{0}:{1}@{2}:6379", _setting.AccessId, _setting.AccessKey, _setting.HostAddress) }, RedisConfig);
58 redisClient = prcm.GetClient();
59 }
60 catch (Exception)
61 {
62 linkServer = false;
63 }
64 }
65
66 /// <summary>
67 /// 是否处于链接状态
68 /// </summary>
69 protected bool LinkServer
70 {
71 get
72 {
73 return linkServer;
74 }
75 }
76
77 /// <summary>
78 /// 根据传入的key-value添加一条记录,当key已存在返回false
79 /// </summary>
80 /// <typeparam name="T"></typeparam>
81 /// <param name="key"></param>
82 /// <param name="value"></param>
83 /// <returns></returns>
84 protected bool Add<T>(string key, T value)
85 {
86 return redisClient.Add<T>(key, value);
87 }
88
89 /// <summary>
90 /// 根据传入的key-value添加一条记录,当key已存在返回false
91 /// </summary>
92 /// <typeparam name="T"></typeparam>
93 /// <param name="key"></param>
94 /// <param name="value"></param>
95 /// <param name="expiresIn">TimeSpan</param>
96 /// <returns></returns>
97 protected bool AddExpires<T>(string key, T value, TimeSpan expiresIn)
98 {
99 return redisClient.Add<T>(key, value, expiresIn);
100 }
101
102 /// <summary>
103 /// 获取
104 /// </summary>
105 /// <typeparam name="T"></typeparam>
106 /// <param name="key"></param>
107 /// <returns></returns>
108 protected T Get<T>(string key)
109 {
110 try
111 {
112 return redisClient.Get<T>(key);
113 }
114 catch(Exception ex)
115 {
116 throw ex;
117 }
118 }
119
120 protected List<T> GetList<T>(string key)
121 {
122 return redisClient.Get<List<T>>(key);
123 }
124
125 /// <summary>
126 /// 根据传入的多个key获取多条记录的值
127 /// </summary>
128 /// <typeparam name="T"></typeparam>
129 /// <param name="keys"></param>
130 /// <returns></returns>
131 protected IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
132 {
133 return redisClient.GetAll<T>(keys);
134 }
135
136 /// <summary>
137 /// 根据传入的key移除一条记录
138 /// </summary>
139 /// <param name="key"></param>
140 /// <returns></returns>
141 public void Remove(string key)
142 {
143 redisClient.Remove(key);
144 }
145
146 /// <summary>
147 /// 根据传入的多个key移除多条记录
148 /// </summary>
149 /// <param name="keys"></param>
150 protected void RemoveAll(IEnumerable<string> keys)
151 {
152 redisClient.RemoveAll(keys);
153 }
154
155 /// <summary>
156 /// Removes items by pattern
157 /// </summary>
158 /// <param name="pattern">pattern</param>
159 public void RemoveByPattern(string pattern)
160 {
161 var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
162 var keysToRemove = new List<String>();
163
164 var allkeys = redisClient.GetAllKeys();
165 foreach (var key in allkeys)
166 if (regex.IsMatch(key))
167 keysToRemove.Add(key);
168
169 foreach (string key in keysToRemove)
170 {
171 Remove(key);
172 }
173 }
174
175
176 /// <summary>
177 /// 清空kv-store缓存
178 /// </summary>
179 /// <returns></returns>
180 public void Clear()
181 {
182 var allkeys = redisClient.GetAllKeys();
183 redisClient.RemoveAll(allkeys);
184 }
185
186 /// <summary>
187 /// 根据传入的key覆盖一条记录的值,当key不存在不会添加
188 /// </summary>
189 /// <typeparam name="T"></typeparam>
190 /// <param name="key"></param>
191 /// <param name="value"></param>
192 /// <returns></returns>
193 protected bool Replace<T>(string key, T value)
194 {
195 return redisClient.Replace<T>(key, value);
196 }
197
198 /// <summary>
199 /// 根据传入的key修改一条记录的值,当key不存在则添加
200 /// </summary>
201 /// <typeparam name="T"></typeparam>
202 /// <param name="key"></param>
203 /// <param name="value"></param>
204 /// <returns></returns>
205 protected bool Set<T>(string key, T value)
206 {
207 try
208 {
209 return redisClient.Set<T>(key, value);
210 }
211 catch(Exception ex)
212 {
213 throw ex;
214 }
215 }
216
217 protected bool Set<T>(string key, List<T> value)
218 {
219 try
220 {
221 JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
222 //执行序列化
223 string objectStr = jsonSerializer.Serialize(value);
224
225 return redisClient.Set(key, value);
226 }
227 catch (Exception ex)
228 {
229 throw ex;
230 }
231 }
232
233 /// <summary>
234 /// 根据传入的key修改一条记录的值,当key不存在则添加
235 /// </summary>
236 /// <typeparam name="T"></typeparam>
237 /// <param name="key"></param>
238 /// <param name="value"></param>
239 /// <param name="expiresIn">TimeSpan</param>
240 /// <returns></returns>
241 protected bool SetExpires<T>(string key, T value, TimeSpan expiresIn)
242 {
243 return redisClient.Set<T>(key, value, expiresIn);
244 }
245
246 /// <summary>
247 /// 根据传入的多个key覆盖多条记录
248 /// </summary>
249 /// <typeparam name="T"></typeparam>
250 /// <param name="values"></param>
251 protected void SetAll<T>(IDictionary<string, T> values)
252 {
253 redisClient.SetAll<T>(values);
254 }
255
256 /// <summary>
257 /// 判断Key在本数据库内是否已被使用(包括各种类型、内置集合等等)
258 /// </summary>
259 /// <param name="key"></param>
260 /// <returns></returns>
261 public bool Contains(string key)
262 {
263 return redisClient.ContainsKey(key);
264 }
265
266 /// <summary>
267 /// 获取所有的Keys集合
268 /// </summary>
269 /// <returns></returns>
270 protected List<string> GetAllKeys()
271 {
272 return redisClient.GetAllKeys();
273 }
274
275 /// <summary>
276 /// 重命名一个Key,值不变
277 /// </summary>
278 /// <param name="fromName"></param>
279 /// <param name="toName"></param>
280 protected void RenameKey(string fromName, string toName)
281 {
282 redisClient.RenameKey(fromName, toName);
283 }
284
285 /// <summary>
286 /// 清除本数据库的所有数据
287 /// </summary>
288 protected void FlushDb()
289 {
290 redisClient.FlushAll();
291 }
292
293 /// <summary>
294 /// 根据Key获取当前存储的值是什么类型:
295 /// </summary>
296 /// <param name="key">None = 0 String = 1 List = 2 Set = 3 SortedSet = 4 Hash = 5</param>
297 /// <returns></returns>
298 protected RedisKeyType GetEntryType(string key)
299 {
300 return redisClient.GetEntryType(key);
301 }
302
303 /// <summary>
304 /// 添加一个项到内部的List<T>
305 /// </summary>
306 /// <param name="listId"></param>
307 /// <param name="value"></param>
308 protected void AddItemToList(string listId, string value)
309 {
310 redisClient.AddItemToList(listId, value);
311 }
312
313 /// <summary>
314 /// 添加一个项到内部的HashSet<T>
315 /// </summary>
316 /// <param name="setId"></param>
317 /// <param name="item"></param>
318 protected void AddItemToSet(string setId, string item)
319 {
320 redisClient.AddItemToSet(setId, item);
321 }
322
323 /// <summary>
324 /// 一次过将参数中的List<T>中的多个值添加入内部的List<T>
325 /// </summary>
326 /// <param name="listId"></param>
327 /// <param name="values"></param>
328 protected void AddRangeToList(string listId, List<string> values)
329 {
330 redisClient.AddRangeToList(listId, values);
331 }
332
333 /// <summary>
334 /// 一次过将参数中的HashSet<T>中的多个值添加入内部的HashSet<T>
335 /// </summary>
336 /// <param name="setId"></param>
337 /// <param name="items"></param>
338 protected void AddRangeToSet(string setId, List<string> items)
339 {
340 redisClient.AddRangeToSet(setId, items);
341 }
342
343 /// <summary>
344 /// 获取指定ListId的内部List<T>的所有值
345 /// </summary>
346 /// <param name="listId"></param>
347 /// <returns></returns>
348 protected List<string> GetAllItemsFromList(string listId)
349 {
350 return redisClient.GetAllItemsFromList(listId);
351 }
352
353 /// <summary>
354 /// 获取指定SetId的内部HashSet<T>的所有值
355 /// </summary>
356 /// <param name="setId"></param>
357 /// <returns></returns>
358 protected HashSet<string> GetAllItemsFromSet(string setId)
359 {
360 return redisClient.GetAllItemsFromSet(setId);
361 }
362
363 /// <summary>
364 /// 根据ListId和下标获取一项
365 /// </summary>
366 /// <param name="listId"></param>
367 /// <param name="listIndex"></param>
368 /// <returns></returns>
369 protected string GetItemFromList(string listId, int listIndex)
370 {
371 return redisClient.GetItemFromList(listId, listIndex);
372 }
373 }
374 }
使用注意点
这个可以直接上传list和set等类型的数据,它也支持泛型方法,但因为网络传输肯定是要先序列化的,跟OCS一样的问题,所以我项目用的是EF,所以得先去忽略不需要序列化的字段和属性等,加上[IgnoreDataMember],不然有死循环就会造成内存溢出。