在面向对象编程的过程中为了减轻数据库的压力通常会采用缓存。使用C#编程的时候我们可以使用.NET自带的缓存 System.Web.HttpRuntime.Cache,但是自带的缓存是不支持分布式部署的,并且还有其他缺点可以自行Google一下。现在比较流行的分布是缓存有Memcached和Redis。这两个缓存你都可以看成是key-value的nosql数据库,支持持久化。
Redis最为常用的数据类型主要有以下:
Memcached仅支持简单的key-value结构的数据
平时我们一般使用Redis的String就可以了,本文重点讲解的是通过StackExchange.Redis使用C#封装Redis的帮助类Helper。
如果我们的程序中需要使用缓存,然而使用什么样的形式缓存(是C#自带的、Memcached还是Redis)是有可能变动的,因此我们需要针对是根据接口来编程,而不是具体某一个缓存的实现,首先我们定义如下的缓存接口:
ICache.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Framework.Common.CacheHelper
{
public interface ICache
{
T StringGet(string key,Funcfunc, TimeSpan absoluteExpireTime, bool cache = true) where T : class;
}
}然后实现ICache接口的Redis缓存。
RedisCache.cs
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Framework.Common.CacheHelper
{
public class RedisCache : ICache
{
public T StringGet(string key, Funcfunc, TimeSpan absoluteExpireTime ,bool cache = true) where T: class
{
if (!cache)
return func.Invoke();
if(RedisManager.Instance.GetDatabase().KeyExists(key))
{
string strVal = RedisManager.Instance.GetDatabase().StringGet(key);
return string.IsNullOrEmpty(strVal) ? null : JsonConvert.DeserializeObject(strVal);
}
else
{
var obj = func.Invoke();
RedisManager.Instance.GetDatabase().StringSet(key, JsonConvert.SerializeObject(obj), absoluteExpireTime);
return obj;
}
}
}
}其中RedisManager.cs的代码如下所示
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Framework.Common.CacheHelper
{
public class RedisManager
{
private static volatile ConnectionMultiplexer _instance;
private static volatile object sys_object = new object();
private static string _conn = ConfigurationManager.AppSettings["redis_config"] ?? "127.0.0.1:6379";
private RedisManager() { }
public static ConnectionMultiplexer Instance
{
get
{
if(_instance==null)
{
lock(sys_object)
{
if(_instance==null)
{
_instance = ConnectionMultiplexer.Connect(_conn);
}
}
}
return _instance;
}
}
public static IDatabase GetDatabase()
{
return _instance.GetDatabase();
}
}
}注意ConnectionMultiplexer只需要创建一个实例,所以RedisManager.cs采用的是单例模式
现在已经封装好了所有的实现类,但是这样Redis.cs还需要自己实现,那么使用的时候就不方便,为此我们可以封装一个Cache的工厂类来实现具体缓存的实例化,具体代码如下所示:
CacheManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Framework.Common.CacheHelper
{
public static class CacheManager
{
private static volatile ICache _instance = null;
private static volatile object sys_obj = new object();
public static ICache Cache
{
get
{
if(_instance ==null )
{
lock(sys_obj)
{
if(_instance == null)
{
_instance = new RedisCache();
}
}
}
return _instance;
}
}
}
}这样我们就可以直接通过CacheManager直接使用缓存类了,客户代码就无需去关心具体缓存类的实例。
以上就是通过StackExchange.Redis,使用C#封装Redis帮助类的示例代码。做到的实现对修改的封闭,对扩展的开放。