面對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等等,正式的工作才剛剛開始……