StackExchange.Redis学习笔记(一) Redis的使用初探

2022-03-10 16:37:37 浏览数 (1)

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服务启动成功

0 人点赞