Redis緩存詳解
下面來正式分享今天的文章吧:
。搭建Redis服務(wù)端,并用客戶端連接
。封裝緩存父類,定義Get,Set等常用方法
。定義RedisCache緩存類,執(zhí)行Redis的Get,Set方法
。構(gòu)造出緩存工廠調(diào)用方法
下面一步一個腳印的來分享:
。搭建Redis服務(wù)端,并用客戶端連接
首先,咋們?nèi)ミ@個地址下載安裝文件https://github.com/dmajkic/redis/downloads,我這里的版本是:redis-2.4.5-win32-win64里面有32位和64位的執(zhí)行文件,我這里服務(wù)器是64位的下面給出截圖和用到部分程序的說明:
現(xiàn)在,咋們直接可以用鼠標(biāo)雙擊redis-server.exe這個應(yīng)用程序,這樣就打開了redis服務(wù)窗體(您也可以下載一個windows服務(wù)承載器,把redis服務(wù)運(yùn)行在windows的服務(wù)中,就不用擔(dān)心每次關(guān)閉redis服務(wù)黑色窗體后無法訪問redis了),運(yùn)行起來是這樣:
有紅色框的信息就表示成功了,這里redis服務(wù)監(jiān)聽的端口默認(rèn)是6379,要修改端口或者更多的配置信息請找到redis.conf配置文件,具體配置信息介紹可以來這里http://www.shouce.ren/api/view/a/6231
再來,打開客戶端連接服務(wù)端,咋們退到64bit文件夾的目錄中,鼠標(biāo)移到64bit文件夾上并且安裝Shift鍵,同時點擊鼠標(biāo)的右鍵,選中"在此處打開命令窗口"這樣快速進(jìn)入到了該文件夾的cmd命令窗口中(當(dāng)然不同的操作系統(tǒng)不同,這里演示的是windows的操作;還有其他進(jìn)入的方式這里不做介紹,因為個人感覺這是最快的);然后,在命令窗口中錄入redis-cli.exe -h localhost -p 6379回車來訪問服務(wù)端,效果圖:
再來看下服務(wù)端窗體截圖:
沒錯這樣客戶端就連接上服務(wù)端了,可以簡單在客戶端執(zhí)行下set,get命令:
如果是客戶端要訪問遠(yuǎn)程的redis服務(wù)端,只需要把localhost換成可訪問的ip就行了如果還需要密碼等更多配置請去上面的那個地址鏈接;
。封裝緩存父類,定義Get,Set等常用方法
先來,上父類的代碼:
public class BaseCache : IDisposable { protected string def_ip = string.Empty; protected int def_port = 0; protected string def_password = string.Empty; public BaseCache() { } public virtual void InitCache(string ip = "", int port = 0, string password = "") { } public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10) where T : class,new() { return false; } public virtual T GetCache<T>(string key) where T : class,new() { return default(T); } public virtual bool Remove(string key) { return false; } public virtual bool FlushAll() { return false; } public virtual bool Any(string key) { return false; } public virtual void Dispose(bool isfalse) { if (isfalse) { } } //手動釋放 public void Dispose() { this.Dispose(true); //不自動釋放 GC.SuppressFinalize(this); } }
這里定義的方法沒有太多的注釋,更多的意思我想看方法名稱就明白了,這個父類主要實現(xiàn)了IDisposable,實現(xiàn)的Dispose()中主要用來釋放資源并且自定義了一個 public virtual void Dispose(bool isfalse)方法,這里面有一句是GC.SuppressFinalize(this);按照官網(wǎng)介紹的意思是阻塞自動釋放資源,其他的沒有什么了,繼續(xù)看下面的
。定義RedisCache緩存類,執(zhí)行Redis的Get,Set方法
首先,咋們分別定義類RedisCache,MemcachedCache(這里暫未實現(xiàn)對memcache緩存的操作),并且繼承BaseCache,重寫Set,Get方法如下代碼:
/// <summary> /// Redis緩存 /// </summary> public class RedisCache : BaseCache { public RedisClient redis = null; public RedisCache() { //這里去讀取默認(rèn)配置文件數(shù)據(jù) def_ip = "172.0.0.1"; def_port = 6379; def_password = ""; } #region Redis緩存 public override void InitCache(string ip = "", int port = 0, string password = "") { if (redis == null) { ip = string.IsNullOrEmpty(ip) ? def_ip : ip; port = port == 0 ? def_port : port; password = string.IsNullOrEmpty(password) ? def_password : password; redis = new RedisClient(ip, port, password); } } public override bool SetCache<T>(string key, T t, int timeOutMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override T GetCache<T>(string key) { var t = default(T); try { if (string.IsNullOrEmpty(key)) { return t; } InitCache(); t = redis.Get<T>(key); } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool Remove(string key) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Remove(key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override void Dispose(bool isfalse) { if (isfalse && redis != null) { redis.Dispose(); redis = null; } } #endregion } /// <summary> /// Memcached緩存 /// </summary> public class MemcachedCache : BaseCache { }
這里,用到的RedisClient類是來自nuget包引用的,這里nuget包是:
然后,來看下重寫的InitCache方法,這里面有一些ip,port(端口),password(密碼)參數(shù),這里直接寫入在cs文件中沒有從配置文件讀取,大家可以擴(kuò)展下;這些參數(shù)通過RedisClient構(gòu)造函數(shù)傳遞給底層Socket訪問需要的信息,下面簡單展示下RedisClient幾個的構(gòu)造函數(shù):
public RedisClient(); public RedisClient(RedisEndpoint config); public RedisClient(string host); public RedisClient(Uri uri); public RedisClient(string host, int port); public RedisClient(string host, int port, string password = null, long db = 0);
至于Get,Set方法最終都是使用RedisClient對象訪問的,個人覺得需要注意的是Set方法里面的過期時間參數(shù),目前還沒有試驗這種情況的效果:
?通過這幾種方法設(shè)置過期時間后,快到過期時間的時候如果此時有使用這個緩存key那么過期時間是否會往后自動增加過期時間有效期,這里暫時沒有試驗(這里是由于前面項目中的.net core框架中的memecache緩存都有這種設(shè)置,想來redis應(yīng)該也有吧)
這里,需要重寫下public override void Dispose(bool isfalse)方法,因為調(diào)用完RedisClient后需要釋放,我們通過Dispose統(tǒng)一來手動釋放,而不是直接在調(diào)用的時候使用using()
。構(gòu)造出緩存工廠調(diào)用方法
接下來,咋們需要定義一個緩存工廠,因為上面剛才定義了一個RedisCache和MemcachedCache明顯這里會有多個不同緩存的方法調(diào)用,所用咋們來定義個工廠模式來調(diào)用對應(yīng)的緩存;這里的工廠模式?jīng)]有使用直接顯示創(chuàng)建new RedisCache(),new MemcachedCache()對象的方法,而是使用了反射的原理,創(chuàng)建對應(yīng)的緩存對象;
先來,定義個枚舉,枚舉里面的聲明的名字要和咋們緩存類的名稱相同,代碼如下:
public enum CacheType { RedisCache, MemcachedCache }
再來,定義個工廠來CacheRepository(緩存工廠),并且定義方法Current如下代碼:
public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) { var nspace = typeof(BaseCache); var fullName = nspace.FullName; var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; }
*:通過傳遞枚舉參數(shù),來確定反射CreateInstance()方法需要用到的typeName參數(shù),從而來定義需要訪問的那個緩存對象,這里要注意的是加上了一個命名空間nowspace,因為緩存類可能和工廠類不是同一個命名空間,但是通常會和緩存基類是同命名空間所以在方法最開始的時候截取獲取了緩存類需要的命名空間(這里看自身項目來定吧);
*:Assembly.GetExecutingAssembly()這個是用來獲取當(dāng)前應(yīng)用程序集的路徑,這里就避免了咋們使用Assembly.Load()方法還需要傳遞程序集的路徑地址了
好了滿上上面要求后,咋們可以在測試頁面調(diào)用代碼如:CacheRepository.Current(CacheType.RedisCache).SetCache<MoFlightSearchResponse>(keyData, value);就如此簡單,咋們使用redis-cli.exe客戶端來看下緩存起來的數(shù)據(jù):
怎么樣,您們的是什么效果呢,下面給出整體代碼
#region CacheRepository 緩存工廠(默認(rèn)存儲Session中) /// <summary> /// 緩存枚舉 /// </summary> public enum CacheType { BaseCache, RedisCache, MemcachedCache } /// <summary> /// 緩存工廠(默認(rèn)存儲Session中) /// </summary> public class CacheRepository { /// <summary> /// 緩存工廠(默認(rèn)存儲Session中, CacheKey = "SeesionKey") /// </summary> /// <param name="cacheType">緩存類型</param> /// <returns></returns> public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) { var nspace = typeof(BaseCache); var fullName = nspace.FullName; var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; } } /// <summary> /// 緩存基類(默認(rèn)存儲Session中) /// </summary> public class BaseCache : IDisposable { protected string def_ip = string.Empty; protected int def_port = 0; protected string def_password = string.Empty; protected string CacheKey = "SeesionKey"; public BaseCache() { } /// <summary> /// 獲取自定義SessionId值 /// </summary> /// <param name="key">key:使用唯一的登陸賬號</param> /// <returns>hash值的SessionId</returns> public virtual string GetSessionId(string key) { return Md5Extend.GetSidMd5Hash(key); } public virtual void InitCache(bool isReadAndWriter = true, string ip = "", int port = 0, string password = "") { } public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10, bool isSerilize = false) where T : class,new() { var isfalse = false; try { key = key ?? CacheKey; if (t == null) { return isfalse; } var session_json = JsonConvert.SerializeObject(t); HttpContext.Current.Session.Timeout = timeOutMinute; HttpContext.Current.Session.Add(key, session_json); isfalse = true; } catch (Exception ex) { throw new Exception(ex.Message); } return isfalse; } public virtual T GetCache<T>(string key = null, bool isSerilize = false) where T : class,new() { var t = default(T); try { key = key ?? CacheKey; var session = HttpContext.Current.Session[key]; if (session == null) { return t; } t = JsonConvert.DeserializeObject<T>(session.ToString()); } catch (Exception ex) { throw new Exception(ex.Message); } return t; } public virtual bool Remove(string key = null) { var isfalse = false; try { key = key ?? CacheKey; HttpContext.Current.Session.Remove(key); isfalse = true; } catch (Exception ex) { throw new Exception(ex.Message); } return isfalse; } /// <summary> /// 增加緩存時間 /// </summary> /// <returns></returns> public virtual bool AddExpire(string key, int nTimeMinute = 10) { return true; } public virtual bool FlushAll() { return false; } public virtual bool Any(string key) { return false; } public virtual bool SetHashCache<T>(string hashId, string key, T t, int nTimeMinute = 10) where T : class,new() { return false; } public virtual List<string> GetHashKeys(string hashId) { return null; } public virtual List<string> GetHashValues(string hashId) { return null; } public virtual T GetHashValue<T>(string hashId, string key) where T : class,new() { var t = default(T); return t; } public virtual bool RemoveHashByKey(string hashId, string key) { return false; } public virtual void Dispose(bool isfalse) { if (isfalse) { } } //手動釋放 public void Dispose() { this.Dispose(true); //不自動釋放 GC.SuppressFinalize(this); } } /// <summary> /// Redis緩存 /// </summary> public class RedisCache : BaseCache { public IRedisClient redis = null; public RedisCache() { //這里去讀取默認(rèn)配置文件數(shù)據(jù) def_ip = "127.0.0.1"; def_port = 6379; def_password = ""; } #region Redis緩存 public static object _lockCache = new object(); public override void InitCache(bool isReadAndWriter = true, string ip = "", int port = 0, string password = "") { if (redis == null) { ip = string.IsNullOrEmpty(ip) ? def_ip : ip; port = port == 0 ? def_port : port; password = string.IsNullOrEmpty(password) ? def_password : password; //單個redis服務(wù) //redis = new RedisClient(ip, port, password); //集群服務(wù) 如果密碼,格式如:pwd@ip:port var readAndWritePorts = new List<string> { "shenniubuxing3@127.0.0.1:6379" }; var onlyReadPorts = new List<string> { "shenniubuxing3@127.0.0.1:6378", "shenniubuxing3@127.0.0.1:6377" }; var redisPool = new PooledRedisClientManager( readAndWritePorts, onlyReadPorts, new RedisClientManagerConfig { AutoStart = true, //最大讀取鏈接 MaxReadPoolSize = 20, //最大寫入鏈接 MaxWritePoolSize = 10 }) { //每個鏈接超時時間 ConnectTimeout = 20, //連接池超時時間 PoolTimeout = 60 }; lock (_lockCache) { redis = isReadAndWriter ? redisPool.GetClient() : redisPool.GetReadOnlyClient(); } } } public override bool AddExpire(string key, int nTimeMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); //isfalse = redis.ExpireEntryIn(key, TimeSpan.FromMinutes(nTimeMinute)); isfalse = redis.ExpireEntryAt(key, DateTime.Now.AddMinutes(nTimeMinute)); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override bool SetCache<T>(string key, T t, int timeOutMinute = 10, bool isSerilize = false) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); if (isSerilize) { var data = JsonConvert.SerializeObject(t); var bb = System.Text.Encoding.UTF8.GetBytes(data); isfalse = redis.Set<byte[]>(key, bb, TimeSpan.FromMinutes(timeOutMinute)); } else { isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); } } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override T GetCache<T>(string key, bool isSerilize = false) { var t = default(T); try { if (string.IsNullOrEmpty(key)) { return t; } InitCache(false); if (isSerilize) { var bb = redis.Get<byte[]>(key); if (bb.Length <= 0) { return t; } var data = System.Text.Encoding.UTF8.GetString(bb); t = JsonConvert.DeserializeObject<T>(data); } else { t = redis.Get<T>(key); } } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool Remove(string key) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Remove(key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override bool SetHashCache<T>(string hashId, string key, T t, int nTimeMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key) || t == null) { return isfalse; } InitCache(); var result = JsonConvert.SerializeObject(t); if (string.IsNullOrEmpty(result)) { return isfalse; } isfalse = redis.SetEntryInHash(hashId, key, result); if (isfalse) { AddExpire(key, nTimeMinute); } } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override List<string> GetHashKeys(string hashId) { var hashKeys = new List<string>(); try { if (string.IsNullOrEmpty(hashId)) { return hashKeys; } InitCache(); hashKeys = redis.GetHashKeys(hashId); } catch (Exception ex) { } finally { this.Dispose(); } return hashKeys; } public override List<string> GetHashValues(string hashId) { var hashValues = new List<string>(); try { if (string.IsNullOrEmpty(hashId)) { return hashValues; } InitCache(); hashValues = redis.GetHashValues(hashId); } catch (Exception ex) { } finally { this.Dispose(); } return hashValues; } public override T GetHashValue<T>(string hashId, string key) { var t = default(T); try { if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key)) { return t; } InitCache(); var result = redis.GetValueFromHash(hashId, key); if (string.IsNullOrEmpty(result)) { return t; } t = JsonConvert.DeserializeObject<T>(result); } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool RemoveHashByKey(string hashId, string key) { var isfalse = false; try { if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.RemoveEntryFromHash(hashId, key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override void Dispose(bool isfalse) { if (isfalse && redis != null) { redis.Dispose(); redis = null; } } #endregion } /// <summary> /// Memcached緩存 /// </summary> public class MemcachedCache : BaseCache { } #endregion
這次分享的Redis緩存從搭建到使用希望給您們有幫助,還請多多支持點贊,謝謝。
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關(guān)文章
asp.net SAF 中緩存服務(wù)的實現(xiàn)
對緩存的興趣源于張子陽寫的一篇文章《SAF 中緩存服務(wù)的實現(xiàn)》中的一個例子:2008-08-08jquery repeater 模仿 Google 展開頁面預(yù)覽子視圖
節(jié)后的這一周, 希望大家能挺住, hehe, 這兩天給大家準(zhǔn)備一個 Repeater 子視圖的例子, 模擬了 Google 搜索結(jié)果后的頁面的預(yù)覽, 其實也只是顯示了一段問題2011-10-10asp.net Urlrewriter在虛擬主機(jī)上的使用方法
在網(wǎng)上看到,很多朋友在asp.net中做urlrewrite,用的是HttpHandle Server.Transfer的方法。其實這種方法是錯誤的。2009-12-12asp.net XMLHttpRequest實現(xiàn)用戶注冊前的驗證
用戶注冊前的驗證,提高用戶體驗。2009-10-10asp.net中button控制先執(zhí)行js再執(zhí)行后臺程序的方法
這篇文章主要介紹了asp.net中button控制先執(zhí)行js再執(zhí)行后臺程序的方法,涉及button控件與js的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-01-01.NET Core對象池的應(yīng)用:擴(kuò)展篇
本文主要講解.NET Core對象池的池化集合、池化StringBuilder、ArrayPool<T>以及MemoryPool<T>,需要了解的小伙伴可以多學(xué)習(xí)這篇文章,相信可以幫助到你2021-09-09.NetCore使用Swagger+API多版本控制的流程分析
這篇文章主要介紹了.NetCore使用Swagger+API多版本控制的流程分析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12