這幾天沒有按照計劃分享技術博文,主要是去醫院了,這裡一想到在醫院經歷的種種,我真的有話要說;醫院裡的醫務人員曾經被吹捧為美麗+和藹+可親的天使,在經受5天左右相互接觸後不得不讓感慨;遇見的有些人員在掛號隊伍猶如長龍的時候坐在收費視窗玩手機,理由是自己是換班的差幾分鐘才上班呢;遇見態度極其惡劣的主任醫師,做諮詢幾個問題聲音馬上提高並言語中攜帶諷刺話語;還有其他幾個遇見哈哈這裡就不多說了,可能是某些醫務人員覺得多您個不少,我有的是客源,所以個別是這種態度吧,還是市醫院真不知道怎麼混進去的。
以上是個人的看法,下面來正式分享今天的文章吧:
。搭建Redis服務端,並用客戶端連線
。封裝快取父類,定義Get,Set等常用方法
。定義RedisCache快取類,執行Redis的Get,Set方法
。構造出快取工廠呼叫方法
下面一步一個腳印的來分享:
。搭建Redis服務端,並用客戶端連線
首先,咋們去這個地址下載安裝檔案https://github.com/dmajkic/redis/downloads,我這裡的版本是:redis-2.4.5-win32-win64裡面有32位和64位的執行檔案,我這裡伺服器是64位的下面給出截圖和用到部分程式的說明:
現在,咋們直接可以用滑鼠雙擊redis-server.exe這個應用程式,這樣就開啟了redis服務窗體(您也可以下載一個windows服務承載器,把redis服務執行在windows的服務中,就不用擔心每次關閉redis服務黑色窗體後無法訪問redis了),執行起來是這樣:
有紅色框的資訊就表示成功了,這裡redis服務監聽的埠預設是6379,要修改埠或者更多的配置資訊請找到redis.conf配置檔案,具體配置資訊介紹可以來這裡http://www.shouce.ren/api/view/a/6231
再來,開啟客戶端連線服務端,咋們退到64bit資料夾的目錄中,滑鼠移到64bit資料夾上並且安裝Shift鍵,同時點選滑鼠的右鍵,選中"在此處開啟命令視窗"這樣快速進入到了該資料夾的cmd命令視窗中(當然不同的作業系統不同,這裡演示的是windows的操作;還有其他進入的方式這裡不做介紹,因為個人感覺這是最快的);然後,在命令視窗中錄入redis-cli.exe -h localhost -p 6379回車來訪問服務端,效果圖:
再來看下服務端窗體截圖:
沒錯這樣客戶端就連線上服務端了,可以簡單在客戶端執行下set,get命令:
如果是客戶端要訪問遠端的redis服務端,只需要把localhost換成可訪問的ip就行了如果還需要密碼等更多配置請去上面的那個地址連結;
。封裝快取父類,定義Get,Set等常用方法
先來,上父類的程式碼:
1 public class BaseCache : IDisposable 2 { 3 protected string def_ip = string.Empty; 4 protected int def_port = 0; 5 protected string def_password = string.Empty; 6 7 public BaseCache() 8 { 9 10 } 11 12 public virtual void InitCache(string ip = "", int port = 0, string password = "") 13 { 14 15 } 16 17 public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10) where T : class,new() 18 { 19 20 return false; 21 } 22 23 public virtual T GetCache<T>(string key) where T : class,new() 24 { 25 26 return default(T); 27 } 28 29 public virtual bool Remove(string key) 30 { 31 32 return false; 33 } 34 35 public virtual bool FlushAll() 36 { 37 38 return false; 39 } 40 41 public virtual bool Any(string key) 42 { 43 44 return false; 45 } 46 47 public virtual void Dispose(bool isfalse) 48 { 49 50 if (isfalse) 51 { 52 53 54 } 55 } 56 57 //手動釋放 58 public void Dispose() 59 { 60 61 this.Dispose(true); 62 //不自動釋放 63 GC.SuppressFinalize(this); 64 } 65 }
這裡定義的方法沒有太多的註釋,更多的意思我想看方法名稱就明白了,這個父類主要實現了IDisposable,實現的Dispose()中主要用來釋放資源並且自定義了一個 public virtual void Dispose(bool isfalse)方法,這裡面有一句是GC.SuppressFinalize(this);按照官網介紹的意思是阻塞自動釋放資源,其他的沒有什麼了,繼續看下面的
。定義RedisCache快取類,執行Redis的Get,Set方法
首先,咋們分別定義類RedisCache,MemcachedCache(這裡暫未實現對memcache快取的操作),並且繼承BaseCache,重寫Set,Get方法如下程式碼:
1 /// <summary> 2 /// Redis快取 3 /// </summary> 4 public class RedisCache : BaseCache 5 { 6 public RedisClient redis = null; 7 8 public RedisCache() 9 { 10 11 //這裡去讀取預設配置檔案資料 12 def_ip = "172.0.0.1"; 13 def_port = 6379; 14 def_password = ""; 15 } 16 17 #region Redis快取 18 19 public override void InitCache(string ip = "", int port = 0, string password = "") 20 { 21 22 if (redis == null) 23 { 24 ip = string.IsNullOrEmpty(ip) ? def_ip : ip; 25 port = port == 0 ? def_port : port; 26 password = string.IsNullOrEmpty(password) ? def_password : password; 27 28 redis = new RedisClient(ip, port, password); 29 } 30 } 31 32 public override bool SetCache<T>(string key, T t, int timeOutMinute = 10) 33 { 34 35 var isfalse = false; 36 37 try 38 { 39 if (string.IsNullOrEmpty(key)) { return isfalse; } 40 41 InitCache(); 42 isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); 43 } 44 catch (Exception ex) 45 { 46 } 47 finally { this.Dispose(); } 48 return isfalse; 49 } 50 51 public override T GetCache<T>(string key) 52 { 53 var t = default(T); 54 try 55 { 56 if (string.IsNullOrEmpty(key)) { return t; } 57 58 InitCache(); 59 t = redis.Get<T>(key); 60 } 61 catch (Exception ex) 62 { 63 } 64 finally { this.Dispose(); } 65 return t; 66 } 67 68 public override bool Remove(string key) 69 { 70 var isfalse = false; 71 try 72 { 73 if (string.IsNullOrEmpty(key)) { return isfalse; } 74 75 InitCache(); 76 isfalse = redis.Remove(key); 77 } 78 catch (Exception ex) 79 { 80 } 81 finally { this.Dispose(); } 82 return isfalse; 83 } 84 85 public override void Dispose(bool isfalse) 86 { 87 88 if (isfalse && redis != null) 89 { 90 91 redis.Dispose(); 92 redis = null; 93 } 94 } 95 96 #endregion 97 } 98 99 100 /// <summary> 101 /// Memcached快取 102 /// </summary> 103 public class MemcachedCache : BaseCache 104 { 105 106 107 }
這裡,用到的RedisClient類是來自nuget包引用的,這裡nuget包是:
然後,來看下重寫的InitCache方法,這裡面有一些ip,port(埠),password(密碼)引數,這裡直接寫入在cs檔案中沒有從配置檔案讀取,大家可以擴充套件下;這些引數通過RedisClient建構函式傳遞給底層Socket訪問需要的資訊,下面簡單展示下RedisClient幾個的建構函式:
1 public RedisClient(); 2 public RedisClient(RedisEndpoint config); 3 public RedisClient(string host); 4 public RedisClient(Uri uri); 5 public RedisClient(string host, int port); 6 public RedisClient(string host, int port, string password = null, long db = 0);
至於Get,Set方法最終都是使用RedisClient物件訪問的,個人覺得需要注意的是Set方法裡面的過期時間引數,目前還沒有試驗這種情況的效果:
?通過這幾種方法設定過期時間後,快到過期時間的時候如果此時有使用這個快取key那麼過期時間是否會往後自動增加過期時間有效期,這裡暫時沒有試驗(這裡是由於前面專案中的.net core框架中的memecache快取都有這種設定,想來redis應該也有吧)
這裡,需要重寫下public override void Dispose(bool isfalse)方法,因為呼叫完RedisClient後需要釋放,我們通過Dispose統一來手動釋放,而不是直接在呼叫的時候使用using()
。構造出快取工廠呼叫方法
接下來,咋們需要定義一個快取工廠,因為上面剛才定義了一個RedisCache和MemcachedCache明顯這裡會有多個不同快取的方法呼叫,所用咋們來定義個工廠模式來呼叫對應的快取;這裡的工廠模式沒有使用直接顯示建立new RedisCache(),new MemcachedCache()物件的方法,而是使用了反射的原理,建立對應的快取物件;
先來,定義個列舉,列舉裡面的宣告的名字要和咋們快取類的名稱相同,程式碼如下:
1 public enum CacheType 2 { 3 RedisCache, 4 5 MemcachedCache 6 }
再來,定義個工廠來CacheRepository(快取工廠),並且定義方法Current如下程式碼:
1 public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) 2 { 3 var nspace = typeof(BaseCache); 4 var fullName = nspace.FullName; 5 var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); 6 7 return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; 8 }
*:通過傳遞列舉引數,來確定反射CreateInstance()方法需要用到的typeName引數,從而來定義需要訪問的那個快取物件,這裡要注意的是加上了一個名稱空間nowspace,因為快取類可能和工廠類不是同一個名稱空間,但是通常會和快取基類是同名稱空間所以在方法最開始的時候擷取獲取了快取類需要的名稱空間(這裡看自身專案來定吧);
*:Assembly.GetExecutingAssembly()這個是用來獲取當前應用程式集的路徑,這裡就避免了咋們使用Assembly.Load()方法還需要傳遞程式集的路徑地址了
好了滿上上面要求後,咋們可以在測試頁面呼叫程式碼如:CacheRepository.Current(CacheType.RedisCache).SetCache<MoFlightSearchResponse>(keyData, value);就如此簡單,咋們使用redis-cli.exe客戶端來看下快取起來的資料:
怎麼樣,您們的是什麼效果呢,下面給出整體程式碼(最後更新時間:2016-09-29):
1 #region CacheRepository 快取工廠(預設儲存Session中) 2 3 /// <summary> 4 /// 快取列舉 5 /// </summary> 6 public enum CacheType 7 { 8 BaseCache, 9 10 RedisCache, 11 12 MemcachedCache 13 } 14 15 /// <summary> 16 /// 快取工廠(預設儲存Session中) 17 /// </summary> 18 public class CacheRepository 19 { 20 21 /// <summary> 22 /// 快取工廠(預設儲存Session中, CacheKey = "SeesionKey") 23 /// </summary> 24 /// <param name="cacheType">快取型別</param> 25 /// <returns></returns> 26 public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) 27 { 28 var nspace = typeof(BaseCache); 29 var fullName = nspace.FullName; 30 var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); 31 32 return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; 33 } 34 } 35 36 /// <summary> 37 /// 快取基類(預設儲存Session中) 38 /// </summary> 39 public class BaseCache : IDisposable 40 { 41 protected string def_ip = string.Empty; 42 protected int def_port = 0; 43 protected string def_password = string.Empty; 44 protected string CacheKey = "SeesionKey"; 45 46 public BaseCache() 47 { 48 49 } 50 51 /// <summary> 52 /// 獲取自定義SessionId值 53 /// </summary> 54 /// <param name="key">key:使用唯一的登陸賬號</param> 55 /// <returns>hash值的SessionId</returns> 56 public virtual string GetSessionId(string key) 57 { 58 return Md5Extend.GetSidMd5Hash(key); 59 } 60 61 public virtual void InitCache(bool isReadAndWriter = true, string ip = "", int port = 0, string password = "") 62 { 63 64 } 65 66 public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10, bool isSerilize = false) where T : class,new() 67 { 68 var isfalse = false; 69 70 try 71 { 72 key = key ?? CacheKey; 73 if (t == null) { return isfalse; } 74 75 var session_json = JsonConvert.SerializeObject(t); 76 HttpContext.Current.Session.Timeout = timeOutMinute; 77 HttpContext.Current.Session.Add(key, session_json); 78 isfalse = true; 79 } 80 catch (Exception ex) 81 { 82 83 throw new Exception(ex.Message); 84 } 85 return isfalse; 86 } 87 88 public virtual T GetCache<T>(string key = null, bool isSerilize = false) where T : class,new() 89 { 90 var t = default(T); 91 92 try 93 { 94 95 key = key ?? CacheKey; 96 var session = HttpContext.Current.Session[key]; 97 if (session == null) { return t; } 98 99 t = JsonConvert.DeserializeObject<T>(session.ToString()); 100 } 101 catch (Exception ex) 102 { 103 104 throw new Exception(ex.Message); 105 } 106 return t; 107 } 108 109 public virtual bool Remove(string key = null) 110 { 111 var isfalse = false; 112 113 try 114 { 115 key = key ?? CacheKey; 116 HttpContext.Current.Session.Remove(key); 117 isfalse = true; 118 } 119 catch (Exception ex) 120 { 121 122 throw new Exception(ex.Message); 123 } 124 return isfalse; 125 } 126 127 /// <summary> 128 /// 增加快取時間 129 /// </summary> 130 /// <returns></returns> 131 public virtual bool AddExpire(string key, int nTimeMinute = 10) 132 { 133 return true; 134 } 135 136 public virtual bool FlushAll() 137 { 138 139 return false; 140 } 141 142 public virtual bool Any(string key) 143 { 144 145 return false; 146 } 147 148 public virtual bool SetHashCache<T>(string hashId, string key, T t, int nTimeMinute = 10) where T : class,new() 149 { 150 151 return false; 152 } 153 154 public virtual List<string> GetHashKeys(string hashId) 155 { 156 157 return null; 158 } 159 160 public virtual List<string> GetHashValues(string hashId) 161 { 162 163 return null; 164 } 165 166 public virtual T GetHashValue<T>(string hashId, string key) where T : class,new() 167 { 168 var t = default(T); 169 return t; 170 } 171 172 public virtual bool RemoveHashByKey(string hashId, string key) 173 { 174 175 return false; 176 } 177 178 179 public virtual void Dispose(bool isfalse) 180 { 181 182 if (isfalse) 183 { 184 185 186 } 187 } 188 189 //手動釋放 190 public void Dispose() 191 { 192 193 this.Dispose(true); 194 //不自動釋放 195 GC.SuppressFinalize(this); 196 } 197 } 198 199 /// <summary> 200 /// Redis快取 201 /// </summary> 202 public class RedisCache : BaseCache 203 { 204 public IRedisClient redis = null; 205 206 public RedisCache() 207 { 208 209 //這裡去讀取預設配置檔案資料 210 def_ip = "127.0.0.1"; 211 def_port = 6379; 212 def_password = ""; 213 } 214 215 #region Redis快取 216 217 public static object _lockCache = new object(); 218 public override void InitCache(bool isReadAndWriter = true, string ip = "", int port = 0, string password = "") 219 { 220 221 if (redis == null) 222 { 223 ip = string.IsNullOrEmpty(ip) ? def_ip : ip; 224 port = port == 0 ? def_port : port; 225 password = string.IsNullOrEmpty(password) ? def_password : password; 226 227 //單個redis服務 228 //redis = new RedisClient(ip, port, password); 229 230 //叢集服務 如果密碼,格式如:pwd@ip:port 231 var readAndWritePorts = new List<string> { "shenniubuxing3@127.0.0.1:6379" }; 232 var onlyReadPorts = new List<string> { 233 "shenniubuxing3@127.0.0.1:6378", 234 "shenniubuxing3@127.0.0.1:6377" 235 }; 236 237 var redisPool = new PooledRedisClientManager( 238 readAndWritePorts, 239 onlyReadPorts, 240 new RedisClientManagerConfig 241 { 242 AutoStart = true, 243 //最大讀取連結 244 MaxReadPoolSize = 20, 245 //最大寫入連結 246 MaxWritePoolSize = 10 247 }) 248 { 249 //每個連結超時時間 250 ConnectTimeout = 20, 251 //連線池超時時間 252 PoolTimeout = 60 253 }; 254 255 lock (_lockCache) 256 { 257 redis = isReadAndWriter ? redisPool.GetClient() : redisPool.GetReadOnlyClient(); 258 } 259 } 260 } 261 262 public override bool AddExpire(string key, int nTimeMinute = 10) 263 { 264 var isfalse = false; 265 try 266 { 267 if (string.IsNullOrEmpty(key)) { return isfalse; } 268 269 InitCache(); 270 //isfalse = redis.ExpireEntryIn(key, TimeSpan.FromMinutes(nTimeMinute)); 271 isfalse = redis.ExpireEntryAt(key, DateTime.Now.AddMinutes(nTimeMinute)); 272 } 273 catch (Exception ex) 274 { 275 } 276 finally { this.Dispose(); } 277 return isfalse; 278 } 279 280 public override bool SetCache<T>(string key, T t, int timeOutMinute = 10, bool isSerilize = false) 281 { 282 283 var isfalse = false; 284 285 try 286 { 287 if (string.IsNullOrEmpty(key)) { return isfalse; } 288 289 InitCache(); 290 if (isSerilize) 291 { 292 var data = JsonConvert.SerializeObject(t); 293 var bb = System.Text.Encoding.UTF8.GetBytes(data); 294 isfalse = redis.Set<byte[]>(key, bb, TimeSpan.FromMinutes(timeOutMinute)); 295 } 296 else { isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); } 297 } 298 catch (Exception ex) 299 { 300 } 301 finally { this.Dispose(); } 302 return isfalse; 303 } 304 305 306 public override T GetCache<T>(string key, bool isSerilize = false) 307 { 308 var t = default(T); 309 try 310 { 311 if (string.IsNullOrEmpty(key)) { return t; } 312 313 InitCache(false); 314 if (isSerilize) 315 { 316 317 var bb = redis.Get<byte[]>(key); 318 if (bb.Length <= 0) { return t; } 319 var data = System.Text.Encoding.UTF8.GetString(bb); 320 t = JsonConvert.DeserializeObject<T>(data); 321 } 322 else { t = redis.Get<T>(key); } 323 } 324 catch (Exception ex) 325 { 326 } 327 finally { this.Dispose(); } 328 return t; 329 } 330 331 public override bool Remove(string key) 332 { 333 var isfalse = false; 334 try 335 { 336 if (string.IsNullOrEmpty(key)) { return isfalse; } 337 338 InitCache(); 339 isfalse = redis.Remove(key); 340 } 341 catch (Exception ex) 342 { 343 } 344 finally { this.Dispose(); } 345 return isfalse; 346 } 347 348 public override bool SetHashCache<T>(string hashId, string key, T t, int nTimeMinute = 10) 349 { 350 351 var isfalse = false; 352 353 try 354 { 355 if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key) || t == null) { return isfalse; } 356 357 InitCache(); 358 359 var result = JsonConvert.SerializeObject(t); 360 if (string.IsNullOrEmpty(result)) { return isfalse; } 361 isfalse = redis.SetEntryInHash(hashId, key, result); 362 if (isfalse) { AddExpire(key, nTimeMinute); } 363 } 364 catch (Exception ex) 365 { 366 } 367 finally { this.Dispose(); } 368 return isfalse; 369 } 370 371 public override List<string> GetHashKeys(string hashId) 372 { 373 var hashKeys = new List<string>(); 374 try 375 { 376 if (string.IsNullOrEmpty(hashId)) { return hashKeys; } 377 378 InitCache(); 379 hashKeys = redis.GetHashKeys(hashId); 380 381 } 382 catch (Exception ex) 383 { 384 } 385 finally { this.Dispose(); } 386 return hashKeys; 387 } 388 389 public override List<string> GetHashValues(string hashId) 390 { 391 var hashValues = new List<string>(); 392 try 393 { 394 if (string.IsNullOrEmpty(hashId)) { return hashValues; } 395 396 InitCache(); 397 hashValues = redis.GetHashValues(hashId); 398 } 399 catch (Exception ex) 400 { 401 } 402 finally { this.Dispose(); } 403 return hashValues; 404 } 405 406 public override T GetHashValue<T>(string hashId, string key) 407 { 408 var t = default(T); 409 try 410 { 411 if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key)) { return t; } 412 413 InitCache(); 414 var result = redis.GetValueFromHash(hashId, key); 415 if (string.IsNullOrEmpty(result)) { return t; } 416 417 t = JsonConvert.DeserializeObject<T>(result); 418 } 419 catch (Exception ex) 420 { 421 } 422 finally { this.Dispose(); } 423 return t; 424 } 425 426 public override bool RemoveHashByKey(string hashId, string key) 427 { 428 var isfalse = false; 429 430 try 431 { 432 if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key)) { return isfalse; } 433 434 InitCache(); 435 isfalse = redis.RemoveEntryFromHash(hashId, key); 436 } 437 catch (Exception ex) 438 { 439 } 440 finally { this.Dispose(); } 441 return isfalse; 442 } 443 444 public override void Dispose(bool isfalse) 445 { 446 447 if (isfalse && redis != null) 448 { 449 450 redis.Dispose(); 451 redis = null; 452 } 453 } 454 455 #endregion 456 } 457 458 /// <summary> 459 /// Memcached快取 460 /// </summary> 461 public class MemcachedCache : BaseCache 462 { 463 464 465 } 466 467 #endregion
這次分享的Redis快取從搭建到使用希望給您們有幫助,還請多多支援點贊,謝謝。
.2016-08-30號修改最新版本程式碼