在面向对象编程的过程中为了减轻数据库的压力通常会采用缓存。使用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帮助类的示例代码。做到的实现对修改的封闭,对扩展的开放。