一种小型后台管理系统通用开发框架中的Cache缓存设计

我们知道的缓存一般分为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
#endregion

using 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
{
///
/// 缓存操作类
///
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
{
///
/// 缓存操作类
///
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”;
///
/// 获取或设置当前登录用户
///
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 下的实现方式有些区别,这个,我会另起一篇博客去记录。
深圳网站建设 https://www.sz886.com/

猜你喜欢

转载自blog.csdn.net/weixin_45032957/article/details/90081192