新聞中心
- 背景:描述軟件開(kāi)發(fā)中所謂的越南問(wèn)題,理解和分類映射器。
- 我們的旅程:我們轉(zhuǎn)型的原因和方式以及經(jīng)驗(yàn)教訓(xùn)。
- 解決的問(wèn)題和收獲:性能、可擴(kuò)展性、可維護(hù)性和更多云原生代碼的改進(jìn)以及以數(shù)據(jù)為中心的透明文化。
越南問(wèn)題的背景與思考
在2010 年左右的DjangoCon上,有人告訴我使用 ORM 就像美國(guó)在越南開(kāi)戰(zhàn)一樣。該評(píng)論指的是Ted Neward在他 2006 年題為“計(jì)算機(jī)科學(xué)的越南”的博文中創(chuàng)造了這個(gè)詞并將他的比較形式化。

成都創(chuàng)新互聯(lián)公司專注于盤錦企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè),購(gòu)物商城網(wǎng)站建設(shè)。盤錦網(wǎng)站建設(shè)公司,為盤錦等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站設(shè)計(jì),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)
這種比較引起了我的共鳴,但我從未考慮過(guò)放棄 ORM。從類比中吸取了完全錯(cuò)誤的教訓(xùn),我花了幾年時(shí)間尋找完美的 ORM,無(wú)論是通過(guò)我自己的決策還是其他人的決策,我都接觸到了名副其實(shí)的環(huán)法自行車賽:Python、Active Record、Linq 中的 Django 和 SQLAlchemy, Hibernate、實(shí)體框架,以及最近在 Bridge Financial Technology 的 Golang 支持的后端中的 Gorm。
當(dāng)我們?cè)谲浖_(kāi)發(fā)中發(fā)現(xiàn)痛苦時(shí),傾其所有是很重要的。讓它痛到你無(wú)法忍受為止。疼痛越嚴(yán)重,您就越能更好地描述和確定疼痛的來(lái)源。我們的痛苦讓我重新評(píng)估了所謂的越南問(wèn)題,并質(zhì)疑 ORM 是否有意義。在對(duì)面向?qū)ο蠛完P(guān)系世界之間的不匹配進(jìn)行全面分析之前,我不會(huì)去。為此,我建議閱讀 Ted Neward 的永恒帖子。但我將總結(jié)重要的要點(diǎn)。
越南:對(duì)象-關(guān)系不匹配
我首先以大多數(shù)歷史學(xué)家今天所看到的方式過(guò)度簡(jiǎn)化了越南戰(zhàn)爭(zhēng)。越南人正在打一場(chǎng)內(nèi)戰(zhàn)以統(tǒng)一他們的國(guó)家。美國(guó)與蘇聯(lián)和共產(chǎn)主義本身進(jìn)行了代理人戰(zhàn)爭(zhēng),以防止其蔓延。也就是說(shuō),越南人將其視為南北問(wèn)題,而美國(guó)則將其視為東/西問(wèn)題。
整件事都不值得。越南今天是一個(gè)統(tǒng)一的共產(chǎn)主義國(guó)家(越共得到了它想要的東西),而沒(méi)有目睹共產(chǎn)主義學(xué)說(shuō)在亞洲以外的中國(guó)傳播,中國(guó)于 1949 年成為共產(chǎn)主義國(guó)家(美國(guó)得到了它想要的東西)。然而,它跨越了近 15 年,3 屆總統(tǒng)政府和超過(guò) 100 萬(wàn)人傷亡(橫跨美國(guó)、越南北部和南部、雙方的盟友以及軍事和文職人員)。從表面上看,更好的策略是完全脫離接觸。
轉(zhuǎn)向軟件開(kāi)發(fā):對(duì)象和關(guān)系同樣是根本不同的東西。他們來(lái)自不同的地方,有著不同的目標(biāo),沒(méi)有錯(cuò)也沒(méi)有壞處。當(dāng)然,技術(shù)可以在這些世界中進(jìn)行堆棧排名,使用您的團(tuán)隊(duì)知道、尊重和信任的堆棧,您將獲得更多里程。對(duì)我們來(lái)說(shuō),我們相信 Postgres 是關(guān)系數(shù)據(jù)庫(kù)(比 MySQL 或 SQL Server 更好)的同類最佳實(shí)現(xiàn)。同樣,我們喜歡并欣賞 Go,特別是它沒(méi)有通過(guò)繼承實(shí)現(xiàn)面向?qū)ο蟮脑O(shè)計(jì)目標(biāo)。如果您在數(shù)據(jù)庫(kù)或編程語(yǔ)言方面遇到困難,我建議您先解決該問(wèn)題,然后再解決交叉路口的問(wèn)題,或者至少是我們的軌跡,我們對(duì)結(jié)果感到滿意。充實(shí)下面的類比是對(duì)這些“方面”的概述:
面向?qū)ο笤瓌t
面向?qū)ο蟮南到y(tǒng)旨在提供:
- 身份管理:將狀態(tài)的等價(jià)性與對(duì)象本身分開(kāi)。當(dāng)兩個(gè)對(duì)象的值相同時(shí)發(fā)生對(duì)象等價(jià),而當(dāng)兩個(gè)對(duì)象相同時(shí)發(fā)生身份等價(jià),也就是說(shuō),它們都指向內(nèi)存中的相同位置。
- 狀態(tài)管理:將幾個(gè)原語(yǔ)關(guān)聯(lián)成一個(gè)更大的捆綁包的能力,該捆綁包代表有關(guān)世界或問(wèn)題的某些東西。
- 行為:操作所述狀態(tài)的操作集合。
- 封裝:將對(duì)象的簡(jiǎn)化的、導(dǎo)出的表面區(qū)域定義到系統(tǒng)的其余部分的能力,從而隱藏不必要的細(xì)節(jié)。
- 多態(tài)性:同質(zhì)處理不同對(duì)象的能力,盡管它們是不同的東西,但它們可以以相似的方式做出反應(yīng)。
大多數(shù)編程語(yǔ)言通過(guò)繼承模型來(lái)實(shí)現(xiàn)這些原則。但值得注意的是,許多非常成功的語(yǔ)言確實(shí)是沒(méi)有繼承的面向?qū)ο蟮模禾貏e是 Go、Erlang 和 Rust。
關(guān)系原則
關(guān)系存儲(chǔ)引擎旨在規(guī)范化數(shù)據(jù)并記錄世界的事實(shí)。SQL 提供操作以與圍繞集合論建立的數(shù)據(jù)進(jìn)行交互,以確保數(shù)學(xué)正確性并在數(shù)據(jù)可變性期間實(shí)現(xiàn)屬性;即ACID 合規(guī)性。在事務(wù)中執(zhí)行的 SQL 操作是原子的、一致的、隔離的和持久的。規(guī)范化通常是通過(guò)適當(dāng)?shù)脑O(shè)計(jì)來(lái)實(shí)現(xiàn)的,黃金標(biāo)準(zhǔn)是第三正?;?Boyce-Codd 形式。
(一些)差異
這些是完全不同的系統(tǒng)。他們的一些區(qū)別包括:
- 對(duì)象對(duì)聚合狀態(tài)有意義,而關(guān)系試圖將其分割成多個(gè)表。
- 對(duì)象世界中的數(shù)據(jù)可變性問(wèn)題圍繞并發(fā)系統(tǒng)中的意外覆蓋問(wèn)題,并通過(guò)封裝進(jìn)行保護(hù)。關(guān)系世界中的可變性需要交易來(lái)保證狀態(tài)改變時(shí)的正確性。在數(shù)據(jù)被持久化之前,不太需要在改變對(duì)象狀態(tài)時(shí)獲得正確性。
- 存在對(duì)象集合以實(shí)現(xiàn)跨這些對(duì)象的行為,而存在關(guān)系集合以建立關(guān)于世界的事實(shí)。
概念問(wèn)題
以下是由這些差異引起的問(wèn)題列表。
映射問(wèn)題。由于以下問(wèn)題,使用任何映射器都很難將表映射到對(duì)象:
- 對(duì)象關(guān)系將通過(guò)將一個(gè)對(duì)象與另一個(gè)對(duì)象組合來(lái)表示。但是,相關(guān)對(duì)象依賴JOIN于 SQL 中的隱式操作,否則相關(guān)對(duì)象將不會(huì)被數(shù)據(jù)初始化。
- 關(guān)系引擎中的多對(duì)多表涉及 3 個(gè)表:兩個(gè)數(shù)據(jù)源和第三個(gè)連接表。然而,這種關(guān)系只需要兩個(gè)對(duì)象以及另一個(gè)對(duì)象的列表。
如果您的編程語(yǔ)言支持繼承,那么以這種方式對(duì)對(duì)象建模可能很誘人,但數(shù)據(jù)庫(kù)中沒(méi)有 IS-A 類型的關(guān)系。
誰(shuí)/什么擁有架構(gòu)定義?編程語(yǔ)言,以及應(yīng)用程序開(kāi)發(fā)人員,還是數(shù)據(jù)庫(kù)的 DDL,以及 DBA?即使您在組織中沒(méi)有區(qū)分這些角色,您仍然會(huì)遇到這個(gè)問(wèn)題,即所謂的“O”受制于“R”,反之亦然。
元數(shù)據(jù)去哪兒了?大多數(shù)字段自然會(huì)有 1:1 的對(duì)應(yīng)關(guān)系。例如,整數(shù)、布爾值等將在數(shù)據(jù)庫(kù)和您的編程語(yǔ)言中具有眾所周知的類型。但是枚舉呢?很可能這些是帶有有限數(shù)量選項(xiàng)的字符串或整數(shù),并且數(shù)據(jù)庫(kù)和編程語(yǔ)言都可以強(qiáng)制執(zhí)行約束。那么你把這些元數(shù)據(jù)放在哪里呢?應(yīng)用程序?數(shù)據(jù)庫(kù)?兩個(gè)都?
所有這些問(wèn)題都需要通過(guò)將一方(對(duì)象或關(guān)系)聲明為權(quán)威來(lái)解決。這導(dǎo)致了 ORM 的分類——它對(duì)這個(gè)權(quán)威有什么看法?對(duì)象還是關(guān)系?
理解和分類 ORM
實(shí)際上,您不能簡(jiǎn)單地“退出”并擺脫問(wèn)題。這篇文章的標(biāo)題有點(diǎn)營(yíng)銷動(dòng)機(jī)。畢竟,您不會(huì)將對(duì)象持久保存到平面文件中并將其稱為“數(shù)據(jù)庫(kù)”,也不會(huì)使用 SQL 構(gòu)建應(yīng)用程序。這些事情必須在某個(gè)時(shí)候相遇。但我認(rèn)為,許多 ORM 采用的通用方法是有限的,主要是出于方便,通常以犧牲一方為代價(jià)。
從廣義上講,有兩種類型的 ORM:代碼優(yōu)先和數(shù)據(jù)庫(kù)優(yōu)先。
- 在代碼優(yōu)先方法中,您將對(duì)象模型定義定義為將映射到數(shù)據(jù)庫(kù)實(shí)體(一個(gè)或多個(gè)表)的類或類型。這種方法即時(shí)生成 SQL 并大量使用反射。Go 社區(qū)中的一個(gè)例子是gorm。
- 數(shù)據(jù)庫(kù)優(yōu)先方法通常依賴于從您的數(shù)據(jù)庫(kù)定義語(yǔ)言 (DDL) 生成對(duì)象定義代碼。Golang 示例是SQLBoiler。
您可能會(huì)對(duì)其中之一產(chǎn)生直觀和直覺(jué)的反應(yīng)。這種觀點(diǎn)可以頑固地持有。就個(gè)人而言,我總是優(yōu)先考慮對(duì)象而不是關(guān)系,并使用代碼優(yōu)先的 ORM。但最終我將想法轉(zhuǎn)變?yōu)閮?yōu)先考慮數(shù)據(jù)庫(kù)。該決定通過(guò)生成用于與數(shù)據(jù)庫(kù)交互的代碼,促使將 ORM 全部丟棄。
我們放棄 ORM 的旅程
以上幾點(diǎn)都是理論上的。我們的旅程從我們從 ORM Gorm 開(kāi)始感受到的實(shí)際痛苦和問(wèn)題開(kāi)始。
問(wèn)題 1:封裝的 API
更新數(shù)據(jù)庫(kù)中的一些記錄是一個(gè)早期的臉面時(shí)刻。執(zhí)行此操作的 SQL 是:
UPDATE


咨詢
建站咨詢
