在应用程式中有许多向资料库读取资料的动作,为了增加程式效能, 有 2 个方向可以调整。
第 1 种是直接调效 SQL 的效能,减少 SQL 的不良写法,让资料库查找资料的速度变快。
第 2 种是直接将上次查到的结果,先暂存在记忆体中,如果资料库的内容没有变动的话,直接回传刚刚已查过的资料内容,可以有效增加系统回应速度。
在 C# .Net 4.0 开始,我们可以善用 System.Runtime.Caching 的 MemoryCache 的快取机制来增加程式回应的速度。
记忆体内的存取速度远远比向资料库取资料快很多,而资料库取得的资料有时会因为网路限制而变更慢,所以在建置应用程式的时候,适时的加入记忆体快取机制在专案中可以有效增加效能。
什么是 MemoryCache
MemoryCache 是实作记忆体内存取快取的方法。快取可以减少产生内容的工作,将已取得的资料暂存在记忆体空间,并指定暂存时间,可依时间到期而回收或是手动回收。
若应用程式重启时,原有存在快取的资料将会一併自动清除。此概念跟电脑的记忆体是相同的,存放在记忆体内的资料,当电脑重开机后也会一併自动清除。
範例1 指定时间后回收快取
此範例是说明读写快取的方法,而快取存活时间为 60 分钟后即立刻回收
ObjectCache Cache = MemoryCache.Default;string CacheName = "Cache1";// 检查快取是否存在bool isSet = Cache[CacheName] != null;// 取得资料库取得物件(省略动作)DataTable dt = new DataTable();// 写入快取 (指定时间后回收快取)CacheItemPolicy policy = new CacheItemPolicy();policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(60); // 60 分钟后回收Cache.Add(new CacheItem(CacheName, dt), policy);// 读取快取dt = (DataTable)Cache[CacheName];// 移除快取Cache.Remove(CacheName);
此範例讲解了存取 4 个主要动作,
1: 是否存在
2: 写入
3: 读取
4: 移除。
向记忆体存取需指定一个名称,Ex: Cache1,存取都需要用相同的名称。
範例中的 60 分钟是可以改变单位的,换成秒也是可以。
若要换成 60 秒的话,写法改成policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromSeconds (60); // 60 秒后回收
範例2 指定时间未使用时回收快取
此範例是讲解资料写入快取后,如果在 60 分钟内没有被读取时则会回收,若有被读取时,则会再延长 60 分钟
ObjectCache Cache = MemoryCache.Default;string CacheName = "Cache2";// 检查快取是否存在bool isSet = Cache[CacheName] != null;// 取得资料库取得物件(省略动作)DataTable dt = new DataTable();// 写入快取 (指定时间未使用时回收快取)CacheItemPolicy policy = new CacheItemPolicy();policy.SlidingExpiration = TimeSpan.FromMinutes(60); // 若 60 分钟内未呼叫此快取就会回收,若有呼叫则会再延长 60 分钟Cache.Add(new CacheItem(CacheName, dt), policy);// 读取快取dt = (DataTable)Cache[CacheName];// 移除快取Cache.Remove(CacheName);
此範例跟第 1 个差异就是存活时间,如果这个快取有被使用则自动延长存活时间。
此两种範例都可以依实务上的需求而选择使用。
範例中的 60 分钟若要换成 60 秒的话,写法改成
policy.SlidingExpiration = TimeSpan. FromSeconds(60); // 60秒
自定常用方法类别
以上介绍了 2 种读写快取的方法,而快取还有另一种存活时间控制是 ChangeMonitors ,当有资料异动时就回收快取,但我没有实际上的应用,就没有实作範例了。
接下来我会展示我将快取常用的方法建立在 Class ,提供 4 个主要方法[ IsSet, Set, Get, Remove] 呼叫
public class AppCache{#region 属性private ObjectCache Cache{get{return MemoryCache.Default;}}// 因为与其他应用程式共用此记忆体快取,所以建议增加此应用程式的前置名称private string IdNameStart = "MyProjectName_";#endregion#region 建构子public AppCache(){}#endregion#region 方法/// <summary>/// 取得快取/// </summary>/// <param name="key"></param>/// <returns></returns>public object Get(string key){return Cache[IdNameStart + key];}/// <summary>/// 移除快取/// </summary>/// <param name="key"></param>public void Remove(string key){Cache.Remove(IdNameStart + key);}/// <summary>/// 是否存在快取/// </summary>/// <param name="key"></param>/// <returns></returns>public bool IsSet(string key){return (Cache[IdNameStart + key] != null);}/// <summary>/// 设定快取/// </summary>/// <param name="key">KEY</param>/// <param name="data">资料</param>public void Set(string key, object data){this.Set(key, data, "Sliding", 60);}/// <summary>/// 设定快取/// </summary>/// <param name="key">KEY</param>/// <param name="data">资料</param>/// <param name="Expiration">保留别</param>/// <param name="cacheTime">保存时间(分钟)</param>public void Set(string key, object data, string Expiration, int cacheTime){CacheItemPolicy policy = new CacheItemPolicy();if (Expiration == "Absolute"){policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);}else if (Expiration == "Sliding"){policy.SlidingExpiration = TimeSpan.FromMinutes(cacheTime);}Cache.Add(new CacheItem(IdNameStart + key, data), policy);}#endregion}
写好此类别,就可以方便使用。
使用的範例可以参考这个
AppCache cache = new AppCache();// 检查Cache 是否存在DataTable dt = null;if (cache.IsSet("Cache1") == false){// 取得资料库取得物件(省略动作)dt = new DataTable();// 设定新 Cache , 60 分钟后就回收快取cache.Set("Cache1", dt, "Absolute", 60);}else{// 取得 Cache dt = (DataTable)cache.Get("Cache1");}// 移除 Cache cache.Remove("Cache1");
将常用的方法写入类别里,方便在应用程式中使用。
重点整理
使用 MemoryCache 是提高系统效能的方法之一可在固定时间后回收 MemoryCache可在未使用时回收 MemoryCache整理好常用方法提供给各位相关学习文章
[C#]QR Code 网址产生与解析 (附範例)
[C#] Base32 编码/解码方法 不分大小写的编码方式