Redis作为缓存服务器
1、ICache的Redis实现没有放在'Framework.Cache/Logic'中。如果是以前,我会认为这样不好。我会这样做,'Framework.Cache'项目引用Redis项目或直接从Nuget安装Redis,
把实现定义在‘Framework.Cache/Logic’中,这样结构看起来很顺眼,‘这算是高内聚么!!!’。不过自从接触了IOC后,现在这样的结构似乎也很合理,没什么违和感。
这就好似把‘IRepository’和‘Repositories’,一个放在Domain,一个放在Infrastructure
2、当前比较稳定的Redis客户端(开源的程序包)有ServiceStack.Redis 和 StackExchange.Redis。我都用了一下,ServiceStatck的
比较好用,不过我感觉后者的性能应该会稍好点
3、关于ServiceStack.Redis中的接口,IRedisClient,ICacheClient,IRedisTypedClient<T>,IEntityStore<T>,IEntityStore。
这些“乱七八糟”的接口和CRUD都有关系,中的有些方法看似好像是重复的,后续希望能整理出一篇结合源码,理论点的文章
一、Framework.Cache
接口ICache,定义缓存操作开放的方法
1 public interface ICache 2 { 3 /// <summary> 4 /// Gets all entries in the cache 5 /// </summary> 6 IEnumerable<KeyValuePair<string, object>> Entries { get; } 7 8 /// <summary> 9 /// Gets a cache item associated with the specified key or adds the item 10 /// if it doesn't exist in the cache. 11 /// </summary> 12 /// <typeparam name="T">The type of the item to get or add</typeparam> 13 /// <param name="key">The cache item key</param> 14 /// <param name="baseMethod">Func which returns value to be added to the cache</param> 15 /// <returns>Cached item value</returns> 16 T Get<T>(string key, Func<T> baseMethod); 17 18 /// <summary> 19 /// Gets a cache item associated with the specified key or adds the item 20 /// if it doesn't exist in the cache. 21 /// </summary> 22 /// <typeparam name="T">The type of the item to get or add</typeparam> 23 /// <param name="key">The cache item key</param> 24 /// <param name="baseMethod">Func which returns value to be added to the cache</param> 25 /// <param name="cacheTime">Expiration time in minutes</param> 26 /// <returns>Cached item value</returns> 27 T Get<T>(string key, Func<T> baseMethod, int cacheTime); 28 29 /// <summary> 30 /// Gets a value indicating whether an item associated with the specified key exists in the cache 31 /// </summary> 32 /// <param name="key">key</param> 33 /// <returns>Result</returns> 34 bool Contains(string key); 35 36 /// <summary> 37 /// Removes the value with the specified key from the cache 38 /// </summary> 39 /// <param name="key">/key</param> 40 void Remove(string key); 41 }
二、基于‘ServiceStack.Redis’的缓存实现
1 public class SSRedisCache : ICache 2 { 3 private const string REGION_NAME = "$#SSRedisCache#$"; 4 private const int _DefaultCacheTime = 30; 5 private readonly static object s_lock = new object(); 6 7 private IRedisClient GetClient() 8 { 9 return RedisManager.GetClient(); 10 } 11 12 private IRedisClient GetReadOnlyClient() 13 { 14 return RedisManager.GetReadOnlyClient(); 15 } 16 17 public IEnumerable<KeyValuePair<string, object>> Entries 18 { 19 get { throw new NotImplementedException(); } 20 } 21 22 public T Get<T>(string key, Func<T> baseMethod) 23 { 24 return Get<T>(key, baseMethod, _DefaultCacheTime); 25 } 26 27 public T Get<T>(string key, Func<T> baseMethod, int cacheTime) 28 { 29 using (var redisClient = GetClient()) 30 { 31 key = BuildKey(key); 32 33 if (redisClient.ContainsKey(key)) 34 { 35 return redisClient.Get<T>(key); 36 } 37 else 38 { 39 lock (s_lock) 40 { 41 if (!redisClient.ContainsKey(key)) 42 { 43 var value = baseMethod(); 44 if (value != null) //请区别null与String.Empty 45 { 46 redisClient.Set<T>(key, value, TimeSpan.FromMinutes(cacheTime)); 47 //redisClient.Save(); 48 } 49 return value; 50 } 51 return redisClient.Get<T>(key); 52 } 53 } 54 } 55 } 56 57 public bool Contains(string key) 58 { 59 using (var redisClient = GetReadOnlyClient()) 60 { 61 return redisClient.ContainsKey(BuildKey(key)); 62 } 63 } 64 65 public void Remove(string key) 66 { 67 using (var redisClient = GetClient()) 68 { 69 redisClient.Remove(BuildKey(key)); 70 } 71 } 72 73 private string BuildKey(string key) 74 { 75 return string.IsNullOrEmpty(key) ? null : REGION_NAME + key; 76 } 77 78 }
三、基于‘StackExchange.Redis’的缓存实现
1 <?xml version="1.0" encoding="utf-8"?> 2 <packages> 3 <package id="MsgPack.Cli" version="0.6.8" targetFramework="net45" /> 4 <package id="StackExchange.Redis" version="1.0.488" targetFramework="net45" /> 5 <package id="StackExchange.Redis.Extensions.Core" version="1.3.2.0" targetFramework="net45" /> 6 <package id="StackExchange.Redis.Extensions.MsgPack" version="1.3.2.0" targetFramework="net45" /> 7 </packages>
1 public class SERedisCache : ICache 2 { 3 private const string REGION_NAME = "$#SERedisCache#$"; 4 private const int _DefaultCacheTime = 30; 5 private readonly static object s_lock = new object(); 6 7 private StackExchangeRedisCacheClient GetClient() 8 { 9 return new StackExchangeRedisCacheClient(RedisServer.Connection, new MsgPackObjectSerializer()); 10 } 11 12 public IEnumerable<KeyValuePair<string, object>> Entries 13 { 14 get { throw new NotImplementedException(); } 15 } 16 17 public T Get<T>(string key, Func<T> baseMethod) 18 { 19 return Get(key, baseMethod, _DefaultCacheTime); 20 } 21 22 public T Get<T>(string key, Func<T> baseMethod, int cacheTime) 23 { 24 using (var cacheClient = GetClient()) 25 { 26 key = BuildKey(key); 27 28 if (cacheClient.Exists(key)) 29 { 30 return cacheClient.Get<T>(key); 31 } 32 else 33 { 34 lock (s_lock) 35 { 36 if (!cacheClient.Exists(key)) 37 { 38 var value = baseMethod(); 39 if (value != null) //请区别null与String.Empty 40 { 41 cacheClient.Add<T>(key, value, TimeSpan.FromMinutes(cacheTime)); 42 } 43 return value; 44 } 45 return cacheClient.Get<T>(key); 46 } 47 } 48 } 49 } 50 51 public bool Contains(string key) 52 { 53 using (var cacheClient = GetClient()) 54 { 55 return cacheClient.Exists(BuildKey(key)); 56 } 57 } 58 59 public void Remove(string key) 60 { 61 using (var cacheClient = GetClient()) 62 { 63 cacheClient.Remove(BuildKey(key)); 64 } 65 } 66 67 private string BuildKey(string key) 68 { 69 return string.IsNullOrEmpty(key) ? null : REGION_NAME + key; 70 } 71 72 }
完整代码(稍后) 会在另一篇文章关于Web API中附上