电商系统架构总结1(EF)
最近主导了一个电商系统的设计开发过程,包括前期分析设计,框架搭建,功能模块的具体开发(主要负责在线支付部分),成功上线后的部署维护,运维策略等等全过程。
虽然这个系统不是什么超大型的电商系统 数亿计的并发,但团队里的主要成员都有多年的开发经验以及电商的经验,系统设计方面还是麻雀虽小,但五脏俱全。
系统客户端有 ios , android,H5,微信小程序,后台方面用.net web api + sql server,图片资源的读写使用阿里云,缓存则自己搭建redis,支付方面既有使用一些第三方支付平台,也有和支付宝微信等。。。。 技术点很多,说实话,基本上一般应用系统开发用到的技术基本都用到了,也遇到了很多的坑。所以觉得把里面的代码整理归纳出来很有必要,对于以后的系统开发,特别同类项目的开发,很有借鉴意义。由于我没有参与前端的开发,所以这里主要以.nt 后台架构的讲述为主。
由于是.nt mvc web api,所以选择了 EF作为orm组件。程序分层架构分为: 数据层 DAL和 IDAL,业务层BLL和IBLL,Entity(实体定义),WebAPI,另外还建了一个Utility项目,用于容纳一些与业务无关并且可以复用的功能性代码以及第三方开源代码,另外还有两个单独的解决方案,一个名为thirdparty的web api项目, 用于和第三方平台的接口交互,包括向短信平台发送短信验证码,向阿里云上传图片,查询 快递单物流状态,向推送平台(极光,微信公众号)推送消息。另一个为windows服务程序,用于执行自动化工作任务。
下面分别讲述。
一、DAL。主要负责封装对EF的底层数据操作。其中有一段对EF 的DBContext 实现单例模式的代码,是我当时从网上摘抄下来的,代码如下
- public class DbContextFactory
- {
- public static WinLinkContext Create()
- {
- WinLinkContext dbContext = CallContext.GetData("DbContext") as WinLinkContext;
- if (dbContext == null)
- {
- dbContext = new WinLinkContext();
- CallContext.SetData("DbContext", dbContext);
- }
- return dbContext;
- }
- }
其实我最初使用EF时,我记得官方文档都是提倡 dbcontext 是即用即销的,形如 (using WinLinkContext = new WinLinkContext() ){...} 那样,有必要把dbcontext只实例化一个并缓存下来,这样能提高性能和节省资源吗? 开始由于项目工期紧张,没有考虑太多,想着这是别人使用过的成熟代码,还是某大咖的博文例子,应该错不了。结果后来还是出现了问题。某同事a写日志处理模块的时候,也调用了这个 DbContextFactory.Create() ,本意是想把异常发生时的信息记录到数据库,但由于和业务代码公用一个dbcontext,问题就来了。比如某同事b写了几行 add/update EF的代码,接着又写了几行其他的代码, 还没执行 savechanges,但这几行其他代码出现bug,引发异常,于是日志捕捉到了,日志模块就进行使用ef进行插入日志信息,执行savechanges,这时重点来了 , 这个savechanges就会把整个dbcontext的更新内容提交到数据库了!于是连日志模块都报错了,而且错误提示是同事b的代码内容。当然也有读者会说日志模块应该独立开不应该和业务混在一起,确实后来我们也把它独立开了。但这个例子表明 dbcontext使用单例模式有很大问题,我认为还是应该遵循微软官方示例,即用即销,就算要缓存,至少每个模块独立开,不能整个应用使用唯一的一个。比如把上面的代码稍加变化,根据名称读写不同的dbcontext。
- public class DbContextFactory
- {
- public static WinLinkContext Create(string dbName)
- {
- WinLinkContext dbContext = CallContext.GetData(dbName) as WinLinkContext;
- if (dbContext == null)
- {
- dbContext = new WinLinkContext();
- CallContext.SetData(dbName, dbContext);
- }
- return dbContext;
- }
- }
另外还有一个BaseDAL的类,用于封装常规的增删改查以及分页等方法,代码大致如下(里面的db对象就是上文提到dbcontext):
- public T Add(T t)
- {
- return db.Set<T>().Add(t);
- }
- public void Update(T t)
- {
- db.Set<T>().AddOrUpdate(t);
- }
- public void Delete(T t)
- {
- db.Set<T>().Remove(t);
- }
- public bool Delete(string id)
- {
- var entity = db.Set<T>().Find(id);
- if (entity == null)
- {
- return false;
- }
- db.Set<T>().Remove(entity);
- return true;
- }
- public int Delete(string[] ids)
- {
- foreach (var item in ids)
- {
- var entity = db.Set<T>().Find(item);//如果实体已经在内存中,那么就直接从内存拿,如果内存中跟踪实体没有,那么才查询数据库。
- db.Set<T>().Remove(entity);
- }
- return ids.Count();
- }
- public T Find(Expression<Func<T, bool>> findLambda)
- {
- return db.Set<T>().FirstOrDefault(findLambda);
- }
- public T Find(string id)
- {
- return db.Set<T>().Find(id);
- }
- public IQueryable<T> Where(Expression<Func<T, bool>> whereLambda)
- {
- return db.Set<T>().Where(whereLambda);
- }
- public IQueryable<T> GetByPage<Type>(int pageSize, int pageIndex, out int total, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Type>> orderByLambda, bool isAsc)
- {
- var queryData = db.Set<T>().Where(whereLambda);
- //是否升序
- if (isAsc)
- {
- queryData = queryData.OrderBy(orderByLambda);
- }
- else
- {
- queryData = queryData.OrderByDescending(orderByLambda);
- }
- total = queryData.Count();
- if (total > )
- {
- if (pageIndex <= )
- {
- queryData = queryData.Take(pageSize);
- }
- else
- {
- queryData = queryData.Skip((pageIndex - ) * pageSize).Take(pageSize);
- }
- }
- return queryData;
- }
电商系统架构总结1(EF)的更多相关文章
- 电商系统架构总结2(Redis)
二 Redis缓存 考虑到将来服务器的升级扩展,使用redis代替.net内置缓存是比较理想的选择.redis是非常成熟好用的缓存系统,安装配置非常简单,直接上官网下载安装包 安装启动就行了. 1 ...
- 电商系统架构总结4(webapi 版本控制)
为了 顺利迭代升级,web api 在维护过程是不断升级的,但用户是不能强迫他们每次都跟随你去升级,这样会让用户不胜其烦.为了保证不同版本的客户端能同时兼容,在web api接口上加入版本控制就很有必 ...
- 电商系统架构总结3(webapi授权机制)
三 Web API 授权方式 web api的客户端,包括 android,ios,h5,自然对访问权限要加上授权机制.对于h5,要求把h5站点和web api部署在同一个域名下,然后对web api ...
- 集DDD,TDD,SOLID,MVVM,DI,EF,Angularjs等于一身的.NET(C#)开源可扩展电商系统–Virto Commerce
今天一大早来看到园友分享的福利<分享一个前后端分离方案源码-前端angularjs+requirejs+dhtmlx 后端asp.net webapi>,我也来分享一个吧.以下内容由笔者写 ...
- 电商系统的演变可以看出架构演变 Dubbo入门 远程过程调用 需要解决的问题
Dubbo入门---搭建一个最简单的Demo框架 - CSDN博客 https://blog.csdn.net/noaman_wgs/article/details/70214612 Dubbo背景和 ...
- 属性 每秒10万吞吐 并发 架构 设计 58最核心的帖子中心服务IMC 类目服务 入口层是Java研发的,聚合层与检索层都是C语言研发的 电商系统里的SKU扩展服务
小结: 1. 海量异构数据的存储问题 如何将不同品类,异构的数据统一存储起来呢? (1)全品类通用属性统一存储: (2)单品类特有属性,品类类型与通用属性json来进行存储: 2. 入口层是Java研 ...
- (1)dotnet开源电商系统-brnshop&brnMall 和老外开发的nopCommerce(dotnet两套电商来PK--第一篇)
一直想做电商软件,但是实在不想学PHP了,所以前后关注了这两个开源电商系统.一个是国人出品的,一个据说是俄罗斯人写得(不知道对不对).目前两个开源软件都在学习了解中,以下的博文可能会涉及到这两套系统, ...
- 基于SpringBoot+MyBatis实现一套电商系统
项目介绍 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现. 前台商城系统包含首页门户.商品推荐.商品搜索.商品展示.购物车.订单流程.会员中心 ...
- SpringBoot+Security+MyBatis+ES+MQ+Redis+Docker+Vue的电商系统
今天鹏哥给大家推荐的项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现. 前台商城系统包含首页门户.商品推荐.商品搜索.商品展示.购物车.订单流程.会员中 ...
随机推荐
- Jmeter的NON-GUI模式
一般来讲,Jmeter执行压测,都是用Jmeter的命令模式,脚本调试好, 测试脚本能够大大缩减所需要的系统资源. 1.1命令介绍: jmeter -n -t <testplan filenam ...
- 自动化部署--shell脚本--2
node1和node2都装apache [root@linux-node1 ~]# yum install httpd -y Loaded plugins: fastestmirror Loadi ...
- mydumper安装、原理介绍
一.安装 安装依赖包: yum install glib2-devel mysql-devel zlib-devel pcre-devel openssl-devel cmake 下载二进制包: ...
- mysql之 openark-kit online ddl
MySQL工具集openark-kit (官方网站 http://code.openark.org/forge/openark-kit),内部包含很多小工具,在5.6之前用于实现online ddl操 ...
- 什么情况下,英文单词中的k发音变g,t发音变d,p发音变b
当k,t,p在s发音的后面,且在重读音节中,k,t,p就要发相对应的浊辅音g,d,b.
- Webstorm/IntelliJ Idea 过期破解方法
一.Webstorm过期破解方法 如下图,WebStorm过期了,每次都是用30分钟,重新打开. 解决方法: 注册时,在打开的License Activation窗口中选择“License serve ...
- F5负载均衡原理
一. 负载均衡技术 负载均衡技术在现有网络结构之上提供了一种廉价.有效.透明的方法,来扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 1.负载均衡发生的流程图 ...
- OpenWrt路由器通过LuCI界面实现Guest SSID功能
转自: http://blog.ltns.info/linux/guest_ssid_over_openwrt_router/ 之前尝试过 Tomato路由器设置VLAN实现Guest SSID功能, ...
- WPF Demo15 MVVM
项目结构如下: <Window x:Class="MVVMDemo.MainWindow" xmlns="http://schemas.microsoft.com/ ...
- 使用googletest进行C++单元测试(Netbeans为例)
googletest设置步骤(Netbeans为例) 下载googletest [https://github.com/google/googletest],解压到<gtest_dir> ...