Redis
- Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化。
- 与其它键值数据存储相比,Redis有一组相对丰富的数据类型。
- Redis可以将数据复制到任意数量的从机中
Redis的安装
官网只提供了linux的安装包,我win10 的系统,在github上下载的windows安装包 3.0.504最新稳定版的
github地址:https://github.com/MicrosoftArchive/redis/releases 官网下载地址:https://redis.io/download
将压缩包解压到文件夹后,双击“redis-server.exe”即可启动redis服务,也可以在环境变量中配置之后,用redis-server 命令来开启服务,以下是服务启动成功界面
Redis的使用
C#可选用ServiceStack.Redis或者StackExchange.Redis等客户端程序操作redis,由于ServiceStack.Redis已经收费了,我这里用的是StackExchange.Redis,通过Nuget安装到项目中
接下来我们创建一个操作redis的帮助类:
代码语言:javascript复制 1 public static class StackExchangeRedisHelper
2 {
3 private static readonly string Coonstr = ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString;//
4 private static object _locker = new Object();
5 private static ConnectionMultiplexer _instance = null;
6 /// <summary>
7 /// 使用一个静态属性来返回已连接的实例,如下列中所示。这样,一旦 ConnectionMultiplexer 断开连接,便可以初始化新的连接实例。
8 /// </summary>
9 public static ConnectionMultiplexer Instance
10 {
11 get
12 {
13 if (_instance == null)
14 {
15 lock (_locker)
16 {
17 if (_instance == null || !_instance.IsConnected)
18 {
19 _instance = ConnectionMultiplexer.Connect(Coonstr);
20 }
21 }
22 }
23 //注册如下事件
24 _instance.ConnectionFailed = MuxerConnectionFailed;
25 _instance.ConnectionRestored = MuxerConnectionRestored;
26 _instance.ErrorMessage = MuxerErrorMessage;
27 _instance.ConfigurationChanged = MuxerConfigurationChanged;
28 _instance.HashSlotMoved = MuxerHashSlotMoved;
29 _instance.InternalError = MuxerInternalError;
30 return _instance;
31 }
32 }
33
34
35 static StackExchangeRedisHelper()
36 {
37 }
38
39 /// <summary>
40 ///
41 /// </summary>
42 /// <returns></returns>
43 public static IDatabase GetDatabase()
44 {
45 return Instance.GetDatabase();
46 }
47
48 /// <summary>
49 /// 这里的 MergeKey 用来拼接 Key 的前缀,具体不同的业务模块使用不同的前缀。
50 /// </summary>
51 /// <param name="key"></param>
52 /// <returns></returns>
53 private static string MergeKey(string key)
54 {
55 return BaseSystemInfo.SystemCode key;
56 }
57 /// <summary>
58 /// 根据key获取缓存对象
59 /// </summary>
60 /// <typeparam name="T"></typeparam>
61 /// <param name="key"></param>
62 /// <returns></returns>
63 public static T Get<T>(string key)
64 {
65 key = MergeKey(key);
66 return Deserialize<T>(GetDatabase().StringGet(key));
67 }
68 /// <summary>
69 /// 根据key获取缓存对象
70 /// </summary>
71 /// <param name="key"></param>
72 /// <returns></returns>
73 public static object Get(string key)
74 {
75 key = MergeKey(key);
76 return Deserialize<object>(GetDatabase().StringGet(key));
77 }
78
79 /// <summary>
80 /// 设置缓存
81 /// </summary>
82 /// <param name="key"></param>
83 /// <param name="value"></param>
84 public static void Set(string key, object value, TimeSpan? expiry = default(TimeSpan?), When when = When.Always, CommandFlags flags = CommandFlags.None)
85 {
86 key = MergeKey(key);
87 GetDatabase().StringSet(key, Serialize(value), expiry, when, flags);
88 }
89
90 /// <summary>
91 /// 判断在缓存中是否存在该key的缓存数据
92 /// </summary>
93 /// <param name="key"></param>
94 /// <returns></returns>
95 public static bool Exists(string key)
96 {
97 key = MergeKey(key);
98 return GetDatabase().KeyExists(key); //可直接调用
99 }
100
101 /// <summary>
102 /// 移除指定key的缓存
103 /// </summary>
104 /// <param name="key"></param>
105 /// <returns></returns>
106 public static bool Remove(string key)
107 {
108 key = MergeKey(key);
109 return GetDatabase().KeyDelete(key);
110 }
111
112 /// <summary>
113 /// 异步设置
114 /// </summary>
115 /// <param name="key"></param>
116 /// <param name="value"></param>
117 public static async Task SetAsync(string key, object value)
118 {
119 key = MergeKey(key);
120 await GetDatabase().StringSetAsync(key, Serialize(value));
121 }
122
123 /// <summary>
124 /// 根据key获取缓存对象
125 /// </summary>
126 /// <param name="key"></param>
127 /// <returns></returns>
128 public static async Task<object> GetAsync(string key)
129 {
130 key = MergeKey(key);
131 object value = await GetDatabase().StringGetAsync(key);
132 return value;
133 }
134
135 /// <summary>
136 /// 实现递增
137 /// </summary>
138 /// <param name="key"></param>
139 /// <returns></returns>
140 public static long Increment(string key)
141 {
142 key = MergeKey(key);
143 //三种命令模式
144 //Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
145 //Async,异步模式直接走的是Task模型。
146 //Fire - and - Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
147 //即发即弃:通过配置 CommandFlags 来实现即发即弃功能,在该实例中该方法会立即返回,如果是string则返回null 如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
148 return GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
149 }
150
151 /// <summary>
152 /// 实现递减
153 /// </summary>
154 /// <param name="key"></param>
155 /// <param name="value"></param>
156 /// <returns></returns>
157 public static long Decrement(string key, string value)
158 {
159 key = MergeKey(key);
160 return GetDatabase().HashDecrement(key, value, flags: CommandFlags.FireAndForget);
161 }
162
163 /// <summary>
164 /// 序列化对象
165 /// </summary>
166 /// <param name="o"></param>
167 /// <returns></returns>
168 static byte[] Serialize(object o)
169 {
170 if (o == null)
171 {
172 return null;
173 }
174 BinaryFormatter binaryFormatter = new BinaryFormatter();
175 using (MemoryStream memoryStream = new MemoryStream())
176 {
177 binaryFormatter.Serialize(memoryStream, o);
178 byte[] objectDataAsStream = memoryStream.ToArray();
179 return objectDataAsStream;
180 }
181 }
182
183 /// <summary>
184 /// 反序列化对象
185 /// </summary>
186 /// <typeparam name="T"></typeparam>
187 /// <param name="stream"></param>
188 /// <returns></returns>
189 static T Deserialize<T>(byte[] stream)
190 {
191 if (stream == null)
192 {
193 return default(T);
194 }
195 BinaryFormatter binaryFormatter = new BinaryFormatter();
196 using (MemoryStream memoryStream = new MemoryStream(stream))
197 {
198 T result = (T)binaryFormatter.Deserialize(memoryStream);
199 return result;
200 }
201 }
202 /// <summary>
203 /// 配置更改时
204 /// </summary>
205 /// <param name="sender"></param>
206 /// <param name="e"></param>
207 private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
208 {
209 LogHelper.WriteInfoLog("Configuration changed: " e.EndPoint);
210 }
211 /// <summary>
212 /// 发生错误时
213 /// </summary>
214 /// <param name="sender"></param>
215 /// <param name="e"></param>
216 private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
217 {
218 LogHelper.WriteInfoLog("ErrorMessage: " e.Message);
219 }
220 /// <summary>
221 /// 重新建立连接之前的错误
222 /// </summary>
223 /// <param name="sender"></param>
224 /// <param name="e"></param>
225 private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
226 {
227 LogHelper.WriteInfoLog("ConnectionRestored: " e.EndPoint);
228 }
229 /// <summary>
230 /// 连接失败 , 如果重新连接成功你将不会收到这个通知
231 /// </summary>
232 /// <param name="sender"></param>
233 /// <param name="e"></param>
234 private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
235 {
236 LogHelper.WriteInfoLog("重新连接:Endpoint failed: " e.EndPoint ", " e.FailureType (e.Exception == null ? "" : (", " e.Exception.Message)));
237 }
238 /// <summary>
239 /// 更改集群
240 /// </summary>
241 /// <param name="sender"></param>
242 /// <param name="e"></param>
243 private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
244 {
245 LogHelper.WriteInfoLog("HashSlotMoved:NewEndPoint" e.NewEndPoint ", OldEndPoint" e.OldEndPoint);
246 }
247 /// <summary>
248 /// redis类库错误
249 /// </summary>
250 /// <param name="sender"></param>
251 /// <param name="e"></param>
252 private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
253 {
254 LogHelper.WriteInfoLog("InternalError:Message" e.Exception.Message);
255 }
256
257 //场景不一样,选择的模式便会不一样,大家可以按照自己系统架构情况合理选择长连接还是Lazy。
258 //建立连接后,通过调用ConnectionMultiplexer.GetDatabase 方法返回对 Redis Cache 数据库的引用。从 GetDatabase 方法返回的对象是一个轻量级直通对象,不需要进行存储。
259
260 /// <summary>
261 /// 使用的是Lazy,在真正需要连接时创建连接。
262 /// 延迟加载技术
263 /// 微软azure中的配置 连接模板
264 /// </summary>
265 //private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
266 //{
267 // //var options = ConfigurationOptions.Parse(constr);
268 // ////options.ClientName = GetAppName(); // only known at runtime
269 // //options.AllowAdmin = true;
270 // //return ConnectionMultiplexer.Connect(options);
271 // ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(Coonstr);
272 // muxer.ConnectionFailed = MuxerConnectionFailed;
273 // muxer.ConnectionRestored = MuxerConnectionRestored;
274 // muxer.ErrorMessage = MuxerErrorMessage;
275 // muxer.ConfigurationChanged = MuxerConfigurationChanged;
276 // muxer.HashSlotMoved = MuxerHashSlotMoved;
277 // muxer.InternalError = MuxerInternalError;
278 // return muxer;
279 //});
280
281
282 #region 当作消息代理中间件使用 一般使用更专业的消息队列来处理这种业务场景
283 /// <summary>
284 /// 当作消息代理中间件使用
285 /// 消息组建中,重要的概念便是生产者,消费者,消息中间件。
286 /// </summary>
287 /// <param name="channel"></param>
288 /// <param name="message"></param>
289 /// <returns></returns>
290 public static long Publish(string channel, string message)
291 {
292 ISubscriber sub = Instance.GetSubscriber();
293 //return sub.Publish("messages", "hello");
294 return sub.Publish(channel, message);
295 }
296
297 /// <summary>
298 /// 在消费者端得到该消息并输出
299 /// </summary>
300 /// <param name="channelFrom"></param>
301 /// <returns></returns>
302 public static void Subscribe(string channelFrom)
303 {
304 ISubscriber sub = Instance.GetSubscriber();
305 sub.Subscribe(channelFrom, (channel, message) =>
306 {
307 Console.WriteLine((string)message);
308 });
309 }
310 #endregion
311
312 /// <summary>
313 /// GetServer方法会接收一个EndPoint类或者一个唯一标识一台服务器的键值对
314 /// 有时候需要为单个服务器指定特定的命令
315 /// 使用IServer可以使用所有的shell命令,比如:
316 /// DateTime lastSave = server.LastSave();
317 /// ClientInfo[] clients = server.ClientList();
318 /// 如果报错在连接字符串后加 ,allowAdmin=true;
319 /// </summary>
320 /// <returns></returns>
321 public static IServer GetServer(string host, int port)
322 {
323 IServer server = Instance.GetServer(host, port);
324 return server;
325 }
326
327 /// <summary>
328 /// 获取全部终结点
329 /// </summary>
330 /// <returns></returns>
331 public static EndPoint[] GetEndPoints()
332 {
333 EndPoint[] endpoints = Instance.GetEndPoints();
334 return endpoints;
335 }
336
337 }
338
339 internal class BaseSystemInfo
340 {
341 internal static readonly string SystemCode="000A";
342 }
测试代码
代码语言:javascript复制 1 static void Main(string[] args)
2 {
3 RedisTest();
4 }
5 public static void RedisTest()
6 {
7 Console.WriteLine("Redis写入缓存:Name:张三丰");
8 StackExchangeRedisHelper.Set("Name", "张三丰", new TimeSpan(0, 0, 0, 0, 1000));
9 Console.WriteLine("Redis获取缓存:Name:" StackExchangeRedisHelper.Get("Name").ToString());
10 Thread.Sleep(1000);
11 Console.WriteLine("一秒后Redis获取缓存:Name:" StackExchangeRedisHelper.Get("Name")??"");
12 Console.ReadKey();
13 }
也可以通过Execute来直接运行redis命令
Redis加入Windows服务
由于关闭控制台redis就自动关闭了,所以把redis加入windows服务更好一些
切换到redis目录下运行命令:redis-server --service-install redis.windows-service.conf --loglevel verbose
移除服务:--service-uninstal
开启服务:redis-server --service-start
关闭服务:redis-server --service-stop
在开启Redis服务时遇到一些坑,
redis.windows-service.conf中配置:
1. logfile "Logs/redis_log.txt"需要有对应的目录
2.将bind 127.0.0.1注释去掉
3.依然有问题,后参考一篇文章 http://blog.csdn.net/fengzhihen2007/article/details/52211048
直到出现successfully started服务启动成功