一种小型后台管理系统通用开发框架中的Cache缓存设计
本篇博客記錄一下我在實習的公司的后臺管理系統開發框架中學習到的一種關于網站的緩存(Cache)的實現方法,我會在弄懂的基礎上,將該方法在.net core上進行實現。因為公司開發都是基于.net framework的,但是在.net 這一塊,.net framework正在逐漸被.net core所取代,而目前公司的前輩們由于開發任務較重,并沒有著手使用.net core的打算,所以,我自己打算為公司搭建一個基于.net core的后臺開發框架,這對自己是一個挑戰,但收獲還是很大的,在這個過程中,我學到了很多。下面我記錄一下我們公司關于網站設計中Cache的一種設計與實現方法(先說在.net mvc下的實現方法,后續會寫另一篇.net core的實現方法):?
-
總體設計:
?
?
我們知道的緩存一般分為3種,分別是 Cookies,Session和Cache,這三種的區別和使用場景我在這里就不說了,網上有大神的博客說的很清楚。Cookies主要用于客戶端,Session和Cache用于服務端,本篇主要講Cahe的使用。Cache存儲于服務器的內存中,允許自定義如何緩存數據項,以及緩存時間有多長。當系統內存缺乏時,緩存會自動移除很少使用或者使用優先級較低的緩存項以釋放內存。Cache的使用可以提高整個系統的運行效率。
Cache在使用上也是(key,value)形式的,關于插入、獲取、移除什么的,都可以在Cache類中去查看,這里貼出Cache這個類的內容:
#region 程序集 System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Web.dll #endregionusing System.Collections; using System.Reflection;namespace System.Web.Caching {//// 摘要:// Implements the cache for a Web application. This class cannot be inherited.[DefaultMember("Item")]public sealed class Cache : IEnumerable{ public static readonly DateTime NoAbsoluteExpiration; public static readonly TimeSpan NoSlidingExpiration; public Cache(); public object this[string key] { get; set; } public int Count { get; } public long EffectivePrivateBytesLimit { get; } public long EffectivePercentagePhysicalMemoryLimit { get; } public object Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback); public object Get(string key); public IDictionaryEnumerator GetEnumerator(); public void Insert(string key, object value); public void Insert(string key, object value, CacheDependency dependencies);public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback);public object Remove(string key);} }?
可以看到里面有Add,Get,Insert之類的東西,這些用法網上也有很清楚的講述,我也不贅述,也說不清楚,哈哈。
下面,結合上面那張示意圖,來說明一下我要講的緩存設計,個人感覺還是比較好的。
<key,value>的形式,就是一個value對應一個key,通過key可以設置value的值,也可以獲取value的值。在這里我們把 每個用戶登錄時生成的一個唯一的 id 做為 cache的key,然后把希望放到緩存中的數據作為value,進行緩存數據的處理。但是,我們放到value中的值,可能是有不同用途不同種類的一些值,比如,登錄用戶的基本信息,該系統存儲的菜單數據,這兩個就是用途完全不相干的兩類數據,怎么存儲呢?再另外使用一個key值不同的cache,這應該也是可以的。但是,我們這里講的方法只使用一個Cache。
具體做法呢,就是把這個value定義為一個 Dictionary<key,value>類型的值,這樣在value里面,我們就可以通過設置不同的key值,來存儲不同用途的緩存數據了。
-
第一步
首先,先定義一個存儲value數據的類,代碼如下:
UserCache.cs
using System.Collections.Generic;namespace Common {public class UserCache{private readonly Dictionary<string, object> cacheDictionary = new Dictionary<string, object>();private readonly object lockObj = new object();/// <summary>/// 索引器/// </summary>/// <param name="key">key</param>/// <returns>緩存對象</returns>public object this[string key]{get{lock (lockObj){return cacheDictionary.ContainsKey(key) ? cacheDictionary[key] : null;}}set{lock(lockObj){if (cacheDictionary.ContainsKey(key)){cacheDictionary[key] = value;}else{cacheDictionary.Add(key, value);}}}}public void Remove(string key){lock (lockObj){if(cacheDictionary.ContainsKey(key)){cacheDictionary.Remove(key);}}}public void Clear(){lock(lockObj){cacheDictionary.Clear();}}} }?
上面的代碼,用到了一個索引器,這使得我們可以像數組那樣用 XXX[index]這樣的方法訪問和設置數據,從代碼中我們可以看到,這個類最終都實現對?cacheDictionary 這個字典的操作,因為我們的數據都存儲在這個字典中。不管你想存儲什么數據只需要定義一個key值,然后存儲到字典中即可。
-
第二步
定義好UserCache.cs后,我們再來寫關于緩存操作的類:
先定義緩存操作類,然后書寫關于緩存操作的代碼:
WebCache.cs(部分)
using System; using System.Web; using System.Web.Caching; using Common;namespace Console {/// <summary>/// 緩存操作類/// </summary>public class WebCache{#region 私有變量private const string UserIdentifyKey = "CacheUserIdentifyKey";#endregion#region 私有方法private static string GetUserIdentify(){if (HttpContext.Current.Session[UserIdentifyKey] != null)return HttpContext.Current.Session[UserIdentifyKey].ToString();var identify = Guid.NewGuid().ToString();HttpContext.Current.Session[UserIdentifyKey] = identify;return identify;}private static UserCache GetUserCache(){var identify = GetUserIdentify();if (HttpContext.Current.Cache.Get(identify) == null){HttpContext.Current.Cache.Insert(identify, new UserCache(), null, Cache.NoAbsoluteExpiration,new TimeSpan(0, 20, 0), CacheItemPriority.High, CacheRemovedCallback);}return HttpContext.Current.Cache.Get(identify) as UserCache;}/// <summary>/// 緩存被移除時觸發/// </summary>/// <param name="key">被移除的緩存的key</param>/// <param name="value">被移除的緩存的值</param>/// <param name="reason">移除原因</param>private static void CacheRemovedCallback(string key, object value, CacheItemRemovedReason reason){// 緩存被移除時執行的操作// 如果是手動移除,則不處理//if (reason == CacheItemRemovedReason.Removed)// return;// 此處訪問頁面會報錯,暫時注釋掉// ShowNotification(MessageType.Warning, "警告", "由于您太久沒操作頁面已過期,請重新登錄!", true); }#endregion} }?
首先看上面的代碼:
上面三段代碼中,核心的代碼是第二段,需要注意的是,都是靜態方法:
GetUserCache() 方法當然,我們還是從第一段代碼開始說起,
GetUserIdentify()private static string GetUserIdentify(){if (HttpContext.Current.Session[UserIdentifyKey] != null)return HttpContext.Current.Session[UserIdentifyKey].ToString();var identify = Guid.NewGuid().ToString();HttpContext.Current.Session[UserIdentifyKey] = identify;return identify;}
?
在一個用戶登錄之初,我們首先給這個用戶生成一個唯一的用戶 id ,然后把這個id保存到 Session中 (Session也是<key,value>形式的)。在第二段代碼中,通過?GetUserIdentify()方法獲取用戶的唯一 id,然后把這個唯一 id作為 Cache的key值。
然后,我們來看第二段代碼:
GetUserCache(): private static UserCache GetUserCache(){var identify = GetUserIdentify();if (HttpContext.Current.Cache.Get(identify) == null){HttpContext.Current.Cache.Insert(identify, new UserCache(), null, Cache.NoAbsoluteExpiration,new TimeSpan(0, 20, 0), CacheItemPriority.High, CacheRemovedCallback);}return HttpContext.Current.Cache.Get(identify) as UserCache;}?
這段代碼,首先判斷Cache中是否有值(是否存在這個key的Cache),若不存在,則創建一個(代碼中的 new UserCache())。.net framework中Cache操作使用?HttpContext.Current.Cache,Insert后有若干個參數,意思分別是:
identify:key值;new UserCache():value值;
第三個參數是:緩存依賴項 CacheDependency ,這里是 null; Cache.NoAbsoluteExpiration:絕對過期時間 ,這里設置為無絕對過期時間;
new TimeSpan(0, 20, 0):這是滑動過期時間,此處設置為 20 minite;
CacheItemPriority.High:緩存優先級,此處為 high;
CacheRemovedCallback: 緩存移除時的回調函數,這個回調函數的參數是固定寫法,必須按照規定寫,三個參數以及參數類型 不可缺少也不可寫錯,否則會報錯;(具體可見上面的第三段代碼)
上面說到,若不存在,則創建一個 ,若存在,那么就直接返回即可。
接下來,在WebCache.cs中定義一些公共方法,用來供外界的方法調用,以實現對緩存的操作,代碼如下:
WebCache.cs(全): ? using System; using System.Web; using System.Web.Caching; using Common;namespace Console {/// <summary>/// 緩存操作類/// </summary>public class WebCache{#region 私有變量private const string UserIdentifyKey = "CacheUserIdentifyKey";#endregion#region 公共方法/// <summary>/// 獲取緩存/// </summary>/// <param name="key">鍵</param>/// <returns></returns>public static object GetCache(string key){return GetUserCache()[key];}/// <summary>/// 設置緩存/// </summary>/// <param name="key">鍵</param>/// <param name="value">值</param>/// <returns></returns>public static bool SetCache(string key, object value){try{var userCache = GetUserCache();userCache[key] = value;return true;}catch{return false;}}/// <summary>/// 清空緩存/// </summary>/// <returns></returns>public static bool ClearCache(){try{// 只清除緩存內容// GetUserCache().Clear();// 直接從Cache里移除var identify = GetUserIdentify();HttpContext.Current.Cache.Remove(identify);return true;}catch{return false;}}/// <summary>/// 移除緩存/// </summary>/// <param name="key">鍵</param>/// <returns></returns>public static bool RemoveCache(string key){try{GetUserCache().Remove(key);return true;}catch{return false;}}#endregion#region 私有方法private static string GetUserIdentify(){if (HttpContext.Current.Session[UserIdentifyKey] != null)return HttpContext.Current.Session[UserIdentifyKey].ToString();var identify = Guid.NewGuid().ToString();HttpContext.Current.Session[UserIdentifyKey] = identify;return identify;}private static UserCache GetUserCache(){var identify = GetUserIdentify();if (HttpContext.Current.Cache.Get(identify) == null){HttpContext.Current.Cache.Insert(identify, new UserCache(), null, Cache.NoAbsoluteExpiration,new TimeSpan(0, 20, 0), CacheItemPriority.High, CacheRemovedCallback);}return HttpContext.Current.Cache.Get(identify) as UserCache; // as是一種強制類型轉化的方式}/// <summary>/// 緩存被移除時觸發/// </summary>/// <param name="key">被移除的緩存的key</param>/// <param name="value">被移除的緩存的值</param>/// <param name="reason">移除原因</param>private static void CacheRemovedCallback(string key, object value, CacheItemRemovedReason reason){// 緩存被移除時執行的操作// 如果是手動移除,則不處理//if (reason == CacheItemRemovedReason.Removed)// return;// 此處訪問頁面會報錯,暫時注釋掉// ShowNotification(MessageType.Warning, "警告", "由于您太久沒操作頁面已過期,請重新登錄!", true); }#endregion} }
?
依次定義了GetCache(),SetCache(),RemoveCache(),ClearCache()四個方法,供外界調用,來實現對緩存的操作。? 到這里,基本上關于這個Cache的實現就已經講完了,下面,給出一段代碼,做一個使用的示例。private const string LoginUserKey = "CacheKey-LoginUserCacheKey"; /// <summary>/// 獲取或設置當前登錄用戶/// </summary>public static User LoginUser{get { return WebCache.GetCache(LoginUserKey) as User; }set { WebCache.SetCache(LoginUserKey, value); }}
?
?SetCache():WebCache.SetCache(key, value);
?
RemoveCache():? RemoveCache(key); //移除字典中某個緩存值
?
ClearCache(); ClearCache(); //清空緩存的字典?
關于這個緩存設計,就記錄到這里了,關于.net core下的實現,因為.net core下并沒有System.Web這個類,所以它的Cache實現方式,與.net 下的實現方式有些區別,這個,我會另起一篇博客去記錄。
說明:本片博客并沒有完整的demo,所有的代碼都已貼出。
?
?
轉載于:https://www.cnblogs.com/CherishTheYouth/p/CherishTheYouth_2019_0509.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的一种小型后台管理系统通用开发框架中的Cache缓存设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 龟兔赛跑——多线程练习
- 下一篇: mongodb导出导入实例记录