1. 程式人生 > >StackExchange.Redis學習筆記(一) Redis的使用初探

StackExchange.Redis學習筆記(一) Redis的使用初探

壓縮包 建立連接 特定 上下 更改 min don runt 移除

原文:StackExchange.Redis學習筆記(一) Redis的使用初探

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的幫助類:

技術分享圖片
  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 }
View Code

測試代碼

 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服務啟動成功

StackExchange.Redis學習筆記(一) Redis的使用初探