记一次ORM的权衡和取舍
面对ORM的选型,有些人是根据自己熟悉程度来评判,有些人是根据他人的推荐来抉择,有些人觉得都差不多,随便了。当自己要真正做选择的时候,以上的这些依据都无法真正说服自己,因为不同的业务需求,不同的团队构成都会造成选型的差异,而且特别大,这里谈一谈自己的选型。
1.1需求背景介绍
- 我所在的公司是做互联网产品,对性能有着极致的要求;
- 后台人数也不算多,尽量人尽其用,技术水平呈梯度分布;
- 因为产品需要长期维护,所以对代码质量要求非常高,必须做评审和单元测试;
- 对技术的可维护性,可扩展性要求很高,因为资源有限;
- 因为资源有限,所以在生产力和性能之间需要做一个平衡;
1.2需求分析
我们知道没有完美的技术,鱼和熊掌无法兼得,所以我们必须择优录取,这里的复杂度在于你要对所选择的技术优缺点有一个360度的环评,最好能展示各自优缺点对比一览图,最后依据数据来证明你的选择对的,是对团队和业务负责的。
不知道你有没有呆过这样的团队:
- 选什么技术从不讨论,大伙各自闷声干,等干出来你才知道原来对方是用的IBatis.NET。
- 你是后面入职的,你只能在前人的基础上做维护,尽管你觉得这个技术不是最优的,但是你也无法了解当初为什么做这样的选择。
- 在入职后,没有规范的技术培训和规范,你一边Google一边编码一边骂娘。
所以对需求的分析和选型在前期特别的重要,没有对比的选择,感觉活得有点不明不白,你无法说服自己,更无法说服团队和领导。
根据互联网业务特点和团队结构,我们的选择有几个重要的关键词:
- 高性能
- 易使用
- 可扩展
高性能就不用说了,互联网产品,毫秒必争!
易用性和易维护相似,希望能在后续运维过程中不要给团队造成维护的困难,同时也遵循简单原则,高级的东西都有简单的特点。
可扩展面对的是产品的变更,很难想象高性能,易使用但是扩展性很差的产品,这种瑕疵会造成代码的臃肿和腐朽。
所以,这个权衡的标准就出来了,性能、易用、扩展。
1.3备选方案
这里的备选方案由于精力和时间的关系,根据经验和评论只罗列EF Core、Dapper、SmartSql三种,另外一个原因是这三种设计理念完全是不一样的,差异性很大。另外有些人也会偏爱NHibernate Core(和EF雷同,不做考虑)或者SqlSuger等,不在本文讨论范围。
备选方案1:EF Core
优点
- 强类型带来维护的安全感,一旦数据库有修改或者字段变更,编译带来的BUG提示,可用极大提升维护效率。
- EF Core的Code first和自动迁移功能,对面向DDD的设计十分友好,对DB迁移的高效带来的体验也非常棒。
- 领域优先的设计理念,在和业务人员沟通的过程中,优势也相对明显。
- 喜欢写SQL的同学,不要忘记EF本身兼容原生脚本,包括存储过程,不过不是优先的选择。
- 支持多种数据库。
缺点
- 入门容易,精通比较难,其知识体系有点复杂,学习曲线会比较陡峭!
- 生成的SQL需要调试和跟踪,面对多表联合查询,性能就不用说了。
- 需要借助性能检测工具比如MiniProfiler来进行性能分析和监控。
- “我想好了Sql怎么写,然后再来写Linq,完了可能还要再查看一下Linq输出的Sql是什么样的“。这是非常糟糕的体验。
适用场景
在性能和生产力之间可以做很好的平衡,比如企业管理系统、个人站点或者外包项目等。
对EF Core来说如果用的好,性能是完全可以做到非常高的,虽然不是极致的效果,但是在开发效率和性能之间可以做一个很好的平衡。
备选方案2:Dapper
Dapper是.NET的一款轻量级ORM工具(GitHub),也可称为简单对象映射器。在速度方面拥有微型ORM之王的称号。它是半自动的,也就是说实体类和SQL语句都要自己写,但它提供自动对象映射。是通过对IDbConnection接口的扩展来操作数据库的。
优点
- 轻量,只有一个文件
- 性能高,Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。
- 支持多种数据库。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server
- 使用Dapper可以自动进行对象映射,通过Emit反射IDataReader的序列队列,来快速的得到和产生对象
缺点
- 代码里边充斥着 SQL 和各种判断分支,这些将会使代码维护难以阅读和维护,更谈不上Linq的优雅。
- 和EF相比,手写SQL 当修改表结构不易发现bug。
- 习惯了EF后再来使用Dapper,会很难适应那种没有了强类型的安全感。
适用场景
对性能有着极限的追求,同时能写一手很好的SQL(对数据库能达到DBA的水准更好),怀念SQL的感觉,习惯SQL的体验的同学。
在可维护这块有做单元测试,很好的规避后期维护的困难。
备选方案3:SmartSql
为什么这边没有选择NHibernate-Core?是因为这家伙和EF Core太像了,在人气上来看,完全没有必要去做选型,当然如果你的团队有NHibernate情节,对NH玩得风生水起例外。
为什么是SmartSql而不是MyBatis?主要是Mybatis在跨平台上找到不到开源方案,几乎没有更新,更不用说跨平台了。而且SmartSql的设计理念就是借鉴的Mybatis,同时又增加了不少强大的功能,比如支持缓存、CQRS等干货,看官宣SmartSql就一句话:
MyBatis .NET Core+ Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics
优点
- 因为SQL自撸,所以性能和Dapper不相上下,非常的高。
- SmartSql 借鉴了 MyBatis 的思想,使用 XML 来管理 SQL ,并且提供了若干个筛选器标签来消除代码层面的各种 if/else 的判断分支。
- SmartSql将管理你的 SQL ,并且通过筛选标签来维护本来你在代码层面的各种条件判断,使你的代码更加优美,你再也不用看到到处充斥的SQL了,对代码优雅有着极限追求的人会有点受不了。
- 支持多种数据库
缺点
- 易排查:排查性和维护性对新人来说,个人感觉不是十分友好,写SQL会考验你的细心。
- 使用 XML 来管理 SQL个人觉得是优点也是缺点,因为代码优雅了,但是有些人并不是很感冒这种方式,特别是在XML里面的if/else的逻辑判断,不亲切。
- 稳定性有待提升,虽然官宣对Dapper有很好的提升,但是从人气来看,成熟度需要进一步观察。
适用场景
喜欢Dapper的性能,但是不喜欢到处充斥的SQL脚本,追求极致优雅,同时又对SmartSql的特性和效率特别欣赏。但是从人气和成熟度来看,如果对源码没有很好的掌控能力,碰到坑就不好搞了。
1.4备选方案评估和选择
在评估和最终选型的时候,建议做360度环评,架构人员、开发人员、运维人员、测试人员不妨都请过来参与一下。
架构人员首先给出自己的备选方案,然后举行备选方案评估会议,再根据会议结论修改备选方案文档。
有些团队主管或者叫技术经理一人就包办了需求分析、方案选型等工作,虽然这种方式效率很高,但是对团队开发的推进和向上汇报其实是很不利的。首先团队会觉得你大包大揽,黑箱操作;领导会觉得你做事没有章法和原则,万一你离职了,你留下的后遗症和黑锅需要你来背,也许你会觉得我都离职了,关我上面事!
我觉得你的技术牌子首先就砸了,你的影响力和同事的相处能力也消减了,你的分享能力和做事风格也就丢分了,这些无形的资产会在将来某一个时刻带你带来晦气。
由于精力有限,我没有对这些ORM进行很好的压测和提供压测数据,所以提供的是网友的压测结果,由于压测和环境配置以及框架本身版本息息相关,所以这里的数据仅供参考:
(图片来源)
结论:Dapper+扩展
根据人气、性能和易用性,我选择了Dapper。EF Core的性能和精通的门槛是我抛弃它的原因,而SmartSql尽管设计理念是我的最爱,但他的人气和坑是我担心的点。因为无法鱼和熊掌兼得,所以只能根据自己的情况进行取舍,但是你无法开怀,因为你要包容Dapper带给你的不足,而这些不足,我个人选择单元测试来弥补;同时对Dapper的进一步封装和优化也是接下来很重要的工作:比如AOP拦截代替到处都在的Transaction等等,正式的工作才刚刚开始……
记一次ORM的权衡和取舍的更多相关文章
- 如何优雅的写一篇安利文-以Sugar ORM为例
前言 我最近喜欢把写的十分优美的技术文章叫做安利文.首先,文章必须是原创而非软广:其次,阅读之后不仅能快速吸纳技术要点并入门开发,还能感同身受的体会作者热情洋溢的赞美和急于分享心得体验的心情,让人感觉 ...
- 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.7,优化视频聊天、控制更多相关细节
在广域网中,由于网络的结构纷繁复杂.而且其实时状况又是千变万化的,所以,要使广域网中的视频聊天达到一个令人满意的效果,存在诸多挑战.这次发布的GG 3.7版本尝试在这一方向上做一些努力,据我自己测试, ...
- [ZZ] Cache
http://blog.sina.com.cn/s/blog_6472c4cc0102duzr.html 处理器微架构访问Cache的方法与访问主存储器有类似之处.主存储器使用地址编码方式,微架构可以 ...
- 【DWT笔记】傅里叶变换与小波变换
[DWT笔记]傅里叶变换与小波变换 一.前言 我们经常接触到的信号,正弦信号,余弦信号,甚至是复杂的心电图.脑电图.地震波信号都是时域上的信号,我们也成为原始信号,但是通常情况下,我们在原始信号中得到 ...
- APIJSON-以坚持和偏执,回敬傲慢和偏见
APIJSON简介: APIJSON是一种JSON传输结构协议. 客户端可以定义任何JSON结构去向服务端发起请求,服务端就会返回对应结构的JSON字符串,所求即所得. 一次请求任意结构任意数据,方便 ...
- 分布式web架构中对session同步的常用处理方法以及优缺点
写在前面 最近在读一本来自淘宝技术团队大牛的书,名字叫<大型网站系统与Java中间件实践>.开篇的章节详细地介绍了一个网站架构由小变大不断演进的过程,其中从单机架构升级到集群架构的过程中着 ...
- .NET Core实战项目之CMS 第九章 设计篇-白话架构设计
前面两篇文章给大家介绍了我们实战的CMS系统的数据库设计,源码也已经上传到服务器上了.今天我们就好聊聊架构设计,在开始之前先给大家分享一下这几天我一直在听的<从零开始学架构>里面关于架构设 ...
- 分布式 基本理论 CAP 之 各分布式系统的cap支持情况
分布式系统.理论.协议 非常非常多, 它们多cap 的支持是怎么样的呢? 需要注意的是,分布式系统 为了应付各种 复杂 应用场景,支持各种各样的功能,可能有的提供了选项或某种机制, 某个时刻,支持CP ...
- 分布式存储之MogileFS分布式文件系统简单应用
一.分布式存储原理: 分布式存储系统,是将数据分散存储在多台独立的设备上.传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储 ...
随机推荐
- bootstrap 翻页(对齐的链接)
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- C++高精度乘法
#include <cstdio> #include <iostream> #include <algorithm> void highPrecision (int ...
- Django2.x中url路由的path()与re_path()参数解释
在新版本Django2.x中,url的路由表示用path和re_path代替,模块的导入由django1.x版本的from django.conf.urls import url,include变成现 ...
- (12)zabbix agent 类型所有key
zabbix服务器端通过与zabbix agent通信来获取客户端服务器的数据,agent分为两个版本,其中一个是主动一个是被动,在配置主机我们可以看到一个是agent,另一个是agent(activ ...
- systemverilog 之interface/timing region/program
1.connecting the testbench and the design 2.verilog connection review 3.systemverilog interfaces 4.s ...
- leetcode刷题——动态规划
知识点 专题-B-动态规划 题目 斐波那契数列 矩阵路径 数组区间 分割整数 最长递增子序列 最大连续子序列和 最长公共子序列 最长回文子序列 最长公共子串 最长回文子串 背包 题解 CS-Notes ...
- BZOJ 1587: 叶子合并leaves
题目大意:求n个数分成k段的最小代价. 题解:DP,没什么好说的. 代码: #include<cstdio> #include<algorithm> using namespa ...
- ASP.NET Web Application中使用链接文件
最近重构一个内部的平台系统,作为一个平台,其下有几个子系统,每个子系统有自己的网站系统.而每个网站使用的是统一的风格,统一的验证机制,反馈系统,等等.所以,为了避免几个子系统中重复出现相同的资源或文件 ...
- Wp8无广告 锁屏可以持续用的手电筒
前面的博文写了怎么实现手电筒,界面不够漂亮 我修改了界面之后 提交到了微软的App商店 在这里送上下载地址: http://www.windowsphone.com/zh-cn/store/app/% ...
- 大数据学习——hbase的shell客户端基本使用
1 基本shell命令 1 在hbase的 bin目录下进入命令行 ./hbase shell 2 查看有哪些表 list 3 创建一个表 create 't_user_info', {NAME = ...