项目架构开发:数据访问层之Cache
数据访问层简单介绍
数据访问层,提供整个项目的数据访问与持久化功能。在分层系统中所有有关数据访问、检索、持久化的任务,最终都将在这一层完成。
来看一个比较经典的数据访问层结构图
大概可以看出如下信息
1、有缓存、日志、异常处理、数据CRUD、查询及数据事务等功能
2、无缝对接如EF、ADO.NET、NH、Dapper等数据访问技术
3、对外只开放接口层,隐藏具体实现,这样就可以解耦业务层与数据访问层
今天斗胆通过一个简单实例来实践一下,如有不妥的地方,欢迎指正
创建接口层,定义可以提供的一些服务接口
这里我们一个有5种服务接口,方法的功能就不介绍了,应该都能看懂
缓存接口:ICache.cs
1 public interface ICache<T> where T : class 2 { 3 IEnumerable<T> Gets(string key); 4 T Get(string key); 5 bool Sets(string key, IEnumerable<T> value, TimeSpan expiresIn); 6 bool Set(string key, T value, TimeSpan expiresIn); 7 bool Remove(string key); 8 }
缓存服务的实现
因为可能支持多种缓存,所以我实现了Web缓存与Redis缓存,这2中缓存分别在项目初期和后期集群中可能会用到
我们来看HttpRuntimeCache.cs (还有一种Web缓存HttpContext.Cache,不够这种只能在Web应用使用,所以一般不推荐)
1 public class HttpRuntimeCache<T> : ICache<T> where T : class 2 { 3 public HttpRuntimeCache() 4 { 5 6 } 7 8 public T Get(string key) 9 { 10 if (System.Web.HttpRuntime.Cache[key] == null) 11 { 12 return default(T); 13 } 14 15 return System.Web.HttpRuntime.Cache[key] as T; 16 } 17 18 public bool Set(string key, T value, TimeSpan expiresIn) 19 { 20 Set(key, value, expiresIn.Seconds); 21 return true; 22 } 23 24 public bool Remove(string key) 25 { 26 System.Web.HttpRuntime.Cache.Remove(key); 27 return true; 28 } 29 30 private void Set(string key, object value, int absoluteSeconds) 31 { 32 System.Web.HttpRuntime.Cache.Insert(key, value, null, DateTime.Now.AddSeconds(absoluteSeconds), TimeSpan.FromSeconds(0)); 33 } 34 }
现在缓存功能已经实现了;大家应该很容易想到怎麼使用了,比如在业务层这样使用
1 ICache<User> cache = new HttpRuntimeCache<User>(); 2 var user = cache.Get("key");
其实这样是不对的,因为这样的话接口ICache相当于没什么用处,没有起到应有的作用(隔离具体实现)
如果要换另一种缓存实现(比如redis),那还要在所有使用了 new HttpRuntimeCache<User>() 的地方改正过来
这样的耦合要去掉;有2种方式,通过IOC在实例化的时候依赖注入;另一种就是新建一个基础设施层,业务层依赖于这一层
因为业务层肯定是需要调用一些Utilities、Helper等类型的工具类,这个应该是躲不掉的,再怎么接口隔离也去除不了这点
基础设施层的实现
Cache.cs
1 public sealed class Cache<T> where T : class 2 { 3 private readonly static ICache<T> cacheProvider; 4 5 static Cache() 6 { 7 cacheProvider = ProviderHelper<T>.GetCacheProvider(); 8 } 9 10 public static IEnumerable<T> Gets(string key) 11 { 12 return cacheProvider.Gets(key); 13 } 14 15 public static T Get(string key) 16 { 17 return cacheProvider.Get(key); 18 } 19 20 public static bool Sets(string key, IEnumerable<T> value, TimeSpan expiresIn) 21 { 22 return cacheProvider.Sets(key, value, expiresIn); 23 } 24 25 public static bool Set(string key, T value, TimeSpan expiresIn) 26 { 27 return cacheProvider.Set(key, value, expiresIn); 28 } 29 30 public static bool Remove(string key) 31 { 32 return cacheProvider.Remove(key); 33 } 34 }
ProviderHelper.cs 实现如下图
至此,缓存功能实现完毕,我们新建一个测试项目看看结果
1 [TestClass] 2 public class CacheTest 3 { 4 [TestMethod] 5 public void Set() 6 { 7 var user = new LoginUser() 8 { 9 Id = Guid.NewGuid(), 10 LoginName = "LoginName", 11 IsEnabled = 1, 12 Password = "mima1987", 13 CreateTime = DateTime.Now 14 }; 15 16 Cache<LoginUser>.Set("UnitTest3.TestMethod1", user, TimeSpan.FromSeconds(10)); 17 var user2 = Cache<LoginUser>.Get("UnitTest3.TestMethod1"); 18 19 Assert.AreEqual(user.Id, user2.Id); 20 } 21 }
看来没有什么问题。
项目架构开发系列
- 项目架构开发:数据访问层之Cache
- 项目架构开发:数据访问层之Logger
- 项目架构开发:数据访问层之Repository
- 项目架构开发:数据访问层之Query
- 项目架构开发:数据访问层之UnitOfWork