最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【前端大佬 | Node 連載 2/9】語雀團(tuán)隊(duì) - 小琿:《Node.js ORM 在語雀的探索與實(shí)踐》

2023-04-10 22:45 作者:前端早早聊  | 我要投稿

第 63 屆早早聊大會將于 2023 年 4 月 15 日(本周六)舉辦 - 低代碼無代碼|無碼有碼 全靠拖拉,6 位講師全天直播,關(guān)鍵詞:低代碼/組件物料/游戲?qū)嵺`/ AB Test /React 玩轉(zhuǎn)。跟早早聊一起,玩轉(zhuǎn)低代碼,上車鏈接:https://www.zaozao.run/conf/c63


本文是 2021 年 12 月 26 日,第三十五屆 - 前端早早聊【前端搞 Node.js】專場,來自螞蟻金服 語雀前端團(tuán)隊(duì) —— 小琿的分享。感謝 AI 的發(fā)展,借助 GPT 的能力,最近我們終于可以非常高效地將各位講師的精彩分享文本化后,分享給大家。(完整版含演示請看錄播視頻和 PPT):https://www.zaozao.run/video/c35

正文如下

大家好,我是來自語雀的小,是一名全棧開發(fā)工程師。

在本次分享的內(nèi)容如下,

  • 第一,解釋什么是 ORM,以及它在Node.js web 應(yīng)用中的使用和優(yōu)缺點(diǎn)。

  • 第二,大致介紹目前比較常見的兩種 ORM 模式 - Active Record 和 Data Mapper,并對它們進(jìn)行簡單對比。

  • 第三,用架構(gòu)圖和偽代碼來詳細(xì)介紹 ORM 的結(jié)構(gòu),包括其中的重要部分和相關(guān)實(shí)現(xiàn)。

  • 第四,使用 ORM 時可能遇到的問題以及相應(yīng)的優(yōu)化措施。

什么是 ORM

為了照顧純前端的同學(xué),我將先展示一個簡單的 demo 來演示 ORM 的使用。我們假定有三張表,用戶表、文章表和評論表,它們之間的關(guān)系可以用圖表現(xiàn)出來。每篇文章只能有一個作者,每個文章可以有多條評論,每一條評論只能屬于某一篇文章。接下來我們來看看 ORM 在使用時,如何表達(dá)數(shù)據(jù)庫中的關(guān)系,并使用它進(jìn)行業(yè)務(wù)查詢和展示。


首先,我們會使用 ORM 來描述三個實(shí)體,包括用戶、文章和評論。我們將使用 user 類來對應(yīng)用戶實(shí)體,使用 comment 類對應(yīng)評論實(shí)體,使用 article 類對應(yīng)文章實(shí)體。在 article 類中,我們將描述剛剛提到的兩個關(guān)系,即每篇文章有一個作者,每篇文章有多條評論。我們將根據(jù)本地數(shù)據(jù)庫的設(shè)置,連接到數(shù)據(jù)庫,進(jìn)行初始化操作。在初始化函數(shù)中,我們會首先連接到數(shù)據(jù)庫,然后對這三張表進(jìn)行數(shù)據(jù)清理。接下來,我們將演示如何使用 ORM 進(jìn)行增刪改查操作。


我們將先創(chuàng)建一個用戶,并使用 ORM 功能查詢出該用戶,然后對其進(jìn)行簡單修改,并重新查詢結(jié)果。接著,我們將創(chuàng)建一個文章,并添加兩個評論。然后,我們將使用三種不同的方式來查詢文章以及與之相關(guān)的作者和評論。在執(zhí)行結(jié)果中,我們可以看到每個操作所對應(yīng)的 SQL 語句和調(diào)用,以及查詢到的結(jié)果。在下面的三個不同的 API 調(diào)用方式中,生成的 SQL 語句都是相似的。最終,我們將得到一篇文章及其相關(guān)的作者、評論以及其他信息。通過這個 demo,我們可以看到如何在 Node.js 中使用 ORM 進(jìn)行增刪改查操作。


回到主題什么是 ORM ?ORM 是對象關(guān)系映射(Object Relation Mapping)的縮寫,它將數(shù)據(jù)中表對應(yīng)著的開發(fā)代碼或內(nèi)存中的 model 類與數(shù)據(jù)庫中的某一張表對應(yīng)。數(shù)據(jù)表中的每一條數(shù)據(jù)對應(yīng)著 model 類的一個實(shí)例,數(shù)據(jù)表中的某個字段對應(yīng)著 model 類的一個成員變量。使用 ORM 可以將數(shù)據(jù)庫中的數(shù)據(jù)映射到開發(fā)代碼中,從而方便地操作數(shù)據(jù)庫的增刪改查。


使用 ORM 有很多優(yōu)點(diǎn),例如 ORM 會對查詢和更新操作進(jìn)行數(shù)據(jù)預(yù)處理,從而防止 SQL 注入的風(fēng)險。另外,ORM 屏蔽了直接編寫 SQL 的細(xì)節(jié),使得開發(fā)人員不必自己寫 SQL,這對于 SQL 不熟練的人來說是一個好處。此外,由于 ORM 以模型為基礎(chǔ),因此支持 MVC 的開發(fā)架構(gòu),并且可以映射所有數(shù)據(jù)庫表到內(nèi)存的 model 中,這有助于組織和復(fù)用代碼,避免了到處寫 SQL 的尷尬處境。

然而,使用 ORM 也存在一些缺點(diǎn)。例如,由于組合 API 生成的 SQL 的特性,有時自動生成的 SQL 可能不是最優(yōu)的方案,這可能會導(dǎo)致性能問題。此外,為了處理各種復(fù)雜的邏輯,model 也會變得很復(fù)雜,處理查詢結(jié)果可能會有不必要的對象深拷貝,這會影響應(yīng)用的性能。同時,ORM 為了適配 SQL 滿足的各種業(yè)務(wù)場景,有很多 API 需要學(xué)習(xí),這也是一種成本。另外,對于一些奇怪的查詢需求,ORM 可能無法滿足,此時只能手寫 SQL。這些是我總結(jié) ORM 的一些優(yōu)點(diǎn)和缺點(diǎn)。


Active Record & Data Mapper

接下來介紹兩種常見的 ORM 模式:Active Record 和 Data Mapper。Active Record 翻譯成中文就是主動記錄模式,是一種架構(gòu)模式。之前展示的 ORM 是 Active Record 模式的。

Active Record 的簡單總結(jié)是一個對象,同時包含了數(shù)據(jù)庫對應(yīng)的屬性字段和相應(yīng)的業(yè)務(wù)的增刪改查操作,也就是說 model 打包了這一個域該有的所有功能。比如,用戶有了 user model 就可以直接使用它,并對它以及 user model 實(shí)例進(jìn)行一些業(yè)務(wù)的編碼。這種類型的 ORM 幾乎都有一個特點(diǎn),就是所有 CRUD 操作都打包在一個 model 中。業(yè)務(wù)中只需要根據(jù)自己的項(xiàng)目和數(shù)據(jù)庫設(shè)計去派生出對應(yīng)的 base model 的子類。user model 繼承了 base model 所有的 API,同時也會包含自己特有的業(yè)務(wù) API,比如查詢某個性別的用戶、某個年齡段用戶等等。


Active Record 類型的 ORM 使用上更加符合我們的直覺,使用起來更方便。數(shù)據(jù)庫有多少張表,就對應(yīng)多少個 model,每個 model 有哪些操作,都在這個派生出來的 model 中實(shí)現(xiàn)。它代表的是我們的數(shù)據(jù)結(jié)構(gòu)與模型對象高度耦合,因此可能更適合一些業(yè)務(wù)邏輯比較簡單的中小型應(yīng)用。


我們之前已經(jīng)展示了一個屬于 Active Record 類型的 ORM demo,因此在這里就不再多作解釋。接下來,我們將介紹另一種 ORM 類型,即 Data Mapper類型。我們將通過一個 demo 來說明這種類型的 ORM,其中涉及到的模型包括 user、article 和 comment?;仡櫼幌滤鼈冎g的關(guān)系:每篇文章有一個作者,每個用戶可以有多篇文章,每篇文章有多條評論,每條評論只能歸屬于一篇文章。雖然 Data Mapper 類型的 ORM 在 JavaScript 中并不是很流行,但我們將使用一個名為 TypeORM 的常用 ORM 來進(jìn)行演示。

首先,我們需要聲明實(shí)體,分別是用戶(user)、文章(article)和評論(comment)。在每個實(shí)體中,我們聲明可能用到的屬性和實(shí)體之間的關(guān)系。例如,用戶可能會有多篇文章,而一篇文章只能有一個作者和多個評論,每個評論只能屬于一篇文章。這與之前講過的 Active Record ORM 類似,但有一個不同點(diǎn)是這些模型不再包含基礎(chǔ)的數(shù)據(jù)操作(例如增刪改查),而只用于展示數(shù)據(jù),例如名字的展示可能需要加上大寫等特殊的展示。

Data Mapper 的實(shí)現(xiàn)主要是為了適配某個實(shí)體或幾個實(shí)體的一些基礎(chǔ)業(yè)務(wù)操作。我們以文章(article)為例,實(shí)現(xiàn)一個 Data Mapper,里面會有一個 API,用于根據(jù)當(dāng)前文章的 ID 獲取其作者(article)和評論(comment)。在 API 中,我們使用 Data Mapper 提供的基礎(chǔ) API 去做一個簡單的查詢。由于數(shù)據(jù)庫中已經(jīng)有了數(shù)據(jù),我們直接去查詢,然后生成一個circle并查找到想要的文章,其中包含作者和兩個評論。

Data Mapper 模式與 Active Record 模式的不同點(diǎn)在于,它將數(shù)據(jù)存儲層與領(lǐng)域?qū)咏怦睿P筒辉俪袚?dān)增刪改操作的功能。Data Mapper 可以同時處理一個或多個實(shí)體類的應(yīng)用,例如連表查詢和統(tǒng)一的數(shù)據(jù)插入操作等業(yè)務(wù)操作。如果某個業(yè)務(wù)需要對數(shù)據(jù)一致性有較強(qiáng)的要求,并涉及多個實(shí)體,Data Mapper 可以直接在其中進(jìn)行操作。


與之前的 Active Record ORM 不同,如果涉及多個模型,我們可能需要單獨(dú)使用一個服務(wù)(Service)將這些模型結(jié)合起來進(jìn)行處理。因此,Data Mapper ORM 更適合處理多實(shí)體類的應(yīng)用。


無碼有碼,全靠拖拉。跟早早聊一起,玩轉(zhuǎn)低代碼,上車鏈接:https://www.zaozao.run/conf/c63


ORM 的構(gòu)成


我們接下來將講解 ORM 的構(gòu)成,其中我們將重點(diǎn)講解 Active Record ORM,這是我們常用的一種類型。這些例子都是偽代碼。


我將 Active Record ORM 的結(jié)構(gòu)分為兩層,第一層為數(shù)據(jù)抽象層,包含常用的 Base Model,通過繼承 Base Model 來創(chuàng)建業(yè)務(wù) model。

  • API 都通過 Base Model 進(jìn)行調(diào)用,其他基礎(chǔ)功能依附于 Base Model。

  • Hooks 是插入到 API 執(zhí)行過程中的鉤子函數(shù),可以對特定 model 的字段在執(zhí)行某個操作時進(jìn)行通用處理。

  • Validations 是 ORM 進(jìn)行數(shù)據(jù)預(yù)處理的必要部分,使用它可以提高應(yīng)用的安全性和降低數(shù)據(jù)庫執(zhí)行 SQL 時的數(shù)據(jù)類型轉(zhuǎn)換壓力。

  • Transaction 是對數(shù)據(jù)事務(wù)的抽象和實(shí)現(xiàn),對于一些數(shù)據(jù)一致性要求高的業(yè)務(wù)很有必要。

  • Relationships 是關(guān)系型數(shù)據(jù)庫的核心,每個 model 與 model 之間的關(guān)系對應(yīng)數(shù)據(jù)庫的 ERD。

  • Migrations 是 ORM 的一個工具類型的功能,用于同步數(shù)據(jù)表結(jié)構(gòu)以及數(shù)據(jù)訂正。

  • Dirty Check 是檢查數(shù)據(jù)是否更新的功能,在 Hooks 中使用較多。

  • Data Transformation 是將查詢結(jié)果轉(zhuǎn)換為 model 實(shí)例,或?qū)⒉樵儣l件轉(zhuǎn)換為數(shù)據(jù)庫能夠識別的數(shù)據(jù)類型的功能。

第二層為數(shù)據(jù)訪問層。

  • Dialect Adopter 是核心功能,將 model 的 API 調(diào)用轉(zhuǎn)換成對應(yīng)的 SQL,并在轉(zhuǎn)換過程中抹平 ORM 會適配的不同數(shù)據(jù)庫之間的方言差異。

  • Connection Manager用于管理ORM在應(yīng)用中的數(shù)據(jù)庫連接。

  • DB Driver是數(shù)據(jù)工具,用于與數(shù)據(jù)庫進(jìn)行交互。

日志模塊是開發(fā)和運(yùn)維中必須的,貫穿整個架構(gòu)。


數(shù)據(jù)抽象層

在 Base Model 中,數(shù)據(jù)表中的某個字段對應(yīng)著 model 類的成員變量,這是對象關(guān)系映射中的重要關(guān)系映射。

DataType(數(shù)據(jù)類型)主要用于表現(xiàn)數(shù)據(jù)類型,作為 JS 基礎(chǔ)類型與數(shù)據(jù)庫數(shù)據(jù)類型的橋梁,記錄了數(shù)據(jù)庫類型和對應(yīng)的 JS 數(shù)據(jù)類型,并能在兩種語言之間轉(zhuǎn)換數(shù)據(jù)類型。它還需要表達(dá)該類型的 SQL,例如,如果數(shù)據(jù)類型是 integer,在 MySQL 中表現(xiàn)是什么樣子的,在 post Grace 或 circulate 中表現(xiàn)又是什么樣子的類型。這樣,最小的 ORM 最小單位類就成型了。

Attribute (屬性)用于表達(dá)數(shù)據(jù)表中的數(shù)據(jù)字段,它能夠與數(shù)據(jù)表中的字段設(shè)置大致一致,包括是否允許為空、是否有默認(rèn)值、數(shù)據(jù)類型等。在 ORM 中,Attribute 還有一個重要的功能,就是數(shù)據(jù)驗(yàn)證,可以設(shè)置一些預(yù)置的規(guī)則或用戶自定義的規(guī)則來驗(yàn)證數(shù)據(jù)的合法性。

在 Active Record ORM 中,Base Model 是其核心組成部分之一。它包含了 CRUD 在內(nèi)的所有基礎(chǔ) API,同時還要能夠讀取用戶派生的 model。在 Base Model 中,還有針對數(shù)據(jù)庫與應(yīng)用開發(fā)語言之間的不同命名習(xí)慣的 name 和 column 成員變量。初始化 model 時,還會有用戶設(shè)置的 Hooks 和 Validation,用戶可以自定義 set/get 方法來對某個字段做一些自定義的操作,在設(shè)置字段值的時候自動執(zhí)行相應(yīng)操作,比如用 text 類型數(shù)據(jù)庫的字段來存儲 JSON 字符串。此外,base model 還會記錄各個 model 之間的關(guān)系,如 has_one、has_many 等關(guān)系。


Hooks 是指一些在函數(shù)執(zhí)行前或執(zhí)行后需要執(zhí)行的操作,Hooks 的使用則可以降低業(yè)務(wù)代碼的復(fù)雜度,減少工作量,它需要注意一下幾點(diǎn)。

  • Hooks 需要能夠疊加某個操作,以便處理多種邏輯,這些邏輯不會相互影響。

  • Hooks 需要有一個原函數(shù),它的入?yún)⒑头祷刂殿愋筒荒鼙恍薷?。Hooks 的實(shí)現(xiàn)方式有很多種,其中比較直觀的一種方式是面向切面編程。在 ORM 的 API 中,一些 API 可以配置或需要配置 hooks,例如 create、update、destroy 等。

  • Hooks 的實(shí)現(xiàn)需要注意不同的 API 入?yún)⒑头祷刂悼赡懿煌?/span>

  • 實(shí)現(xiàn) Hooks 時需要注意靜態(tài)成員方法和成員方法、函數(shù)執(zhí)行上下文等問題。

  • 在使用 AOP 實(shí)現(xiàn) Hooks 時,我們還需要考慮如何跳過 Hooks 的執(zhí)行。

接著我們來看一下 Transaction 的簡單實(shí)現(xiàn)。在 SQL 語法中實(shí)現(xiàn)事務(wù)并不復(fù)雜,一般使用 begin 開始事務(wù),執(zhí)行業(yè)務(wù) SQL,然后使用 commit 提交或 rollback 回滾事務(wù)。在代碼中實(shí)現(xiàn)事務(wù),我們可以提供一些基礎(chǔ)的 API,如 begin、commit 和 rollback。在事務(wù)開始時,可能需要設(shè)置事務(wù)的隔離級別。通過這些 API,我們可以保持業(yè)務(wù)代碼的數(shù)據(jù)一致性。然而,在實(shí)現(xiàn)事務(wù)時,我們需要考慮如何自動 commit 和 rollback,而不需要手動調(diào)用 commit 和 rollback。


數(shù)據(jù)訪問層

在數(shù)據(jù)抽象層中,為了適配常用的數(shù)據(jù)庫類型,需要一個中間態(tài)去表達(dá) ORM API,這個中間態(tài)被稱為 Spell。它可以表達(dá)實(shí)際的 SQL 命令,根據(jù)模型的類型去判斷操作的數(shù)據(jù)表,表達(dá)查詢所需的字段以及常用的 SQL 關(guān)鍵詞表達(dá)式。



Dialect 需要解析 Spell 表達(dá)式,根據(jù)方言類型生成特定的 SQL。例如,ORM 需要官方提供支持的MySQL、Postgres、SQL Server和 SQLite 的 Dialect。因此,需要為每種數(shù)據(jù)庫類型編寫一個dialect。我們可以將 Spell 表達(dá)式的解析抽象成標(biāo)準(zhǔn)的接口,這樣開發(fā)者就可以實(shí)現(xiàn)自己的方言,甚至不僅限于 SQL,還可以是其他類型的查詢語言。這樣我們就可以使用 ORM 的 API 進(jìn)行各種類型的查詢。


整個查詢的執(zhí)行過程是這樣的:假設(shè)我們使用 user model 去查詢某個用戶數(shù)據(jù),我們在 user model 中使用 find 方法并根據(jù)傳參生成對應(yīng)的 Spell 對象。然后我們在 Connection 類中管理數(shù)據(jù)庫連接池和方言(即 Dialect),實(shí)現(xiàn)一個 query 方法,在其中調(diào)用 Dialect 生成 SQL,使用 SQL Driver 執(zhí)行 SQL,最后通過進(jìn)行數(shù)據(jù)轉(zhuǎn)換并返回結(jié)果。


模塊之間的關(guān)系


讓我們再深入了解各個模塊之間的關(guān)系。首先,數(shù)據(jù)層面上最主要的實(shí)體是 Model。在執(zhí)行查詢操作時, Spell 作為一個中間態(tài),它連接了數(shù)據(jù)抽象層和數(shù)據(jù)訪問層。同時,Dialect 負(fù)責(zé)適配數(shù)據(jù)庫方言和生成特定的 SQL。這個結(jié)構(gòu)還可以擴(kuò)展出更多的功能,不僅限于 SQL 查詢。

else

我們思考一下一個相對成熟的 ORM 還需要哪些改進(jìn)?


歡迎報名第 63 屆早早聊大會 - 低代碼無代碼,了解如何通過低代碼平臺提高生產(chǎn)力,玩轉(zhuǎn)低代碼。上車戳:https://www.zaozao.run/conf/c63

ORM 問題 / 優(yōu)化

緩存查詢

通過適當(dāng)?shù)牟僮鱽斫档蛿?shù)據(jù)庫的 QPS,例如在多個 service 方法中重復(fù)調(diào)用某個 Model 的查詢時可以使用緩存技術(shù),多次調(diào)用時只使用一次結(jié)果。


為了避免多次查詢,可以通過緩存來保存查詢結(jié)果,多次調(diào)用同一個查詢時就可以直接使用緩存結(jié)果,從而降低數(shù)據(jù)庫的 QPS。使用這種方法的時候,還需要考慮到緩存的刷新問題,例如,在更新數(shù)據(jù)時,可以在 update 中添加一個 Hooks,新時自動刷新緩存。


合理使用 Hooks

使用 Hooks 是在使用 ORM 時常見的問題。Hooks 可以大大簡化代碼,例如我們可以根據(jù)文檔內(nèi)容是否更改來更新其更新時間等字段。在某些復(fù)雜情況下,我們可能需要在一個 Model 中的 Hooks 中調(diào)用另一個 Model 的增刪改操作,例如創(chuàng)建文檔后可能需要更新 Book 的操作并觸發(fā)相應(yīng)字段的更新,這時我們需要考慮它們之間的關(guān)聯(lián)關(guān)系和更新順序。


當(dāng)我們的業(yè)務(wù)越來越復(fù)雜時,例如在更新 Repo 的時候可能需要觸發(fā)一些 service 方法,而這些 service 方法可能會在 Hooks 方法中直接調(diào)用,導(dǎo)致調(diào)用鏈越來越長,越來越復(fù)雜。這種不規(guī)范的寫法會使得代碼的復(fù)雜度非常難以控制,甚至可能出現(xiàn)循環(huán)調(diào)用等問題,給新手帶來極大的困擾。因此,在使用 Hooks 時需要非常謹(jǐn)慎,避免出現(xiàn)類似的問題。使用 Hooks 需要謹(jǐn)慎,雖然在平時使用時會感覺很方便,但是當(dāng)需要重構(gòu)或進(jìn)行技術(shù)重構(gòu)時,就可能會遇到困難,甚至引起災(zāi)難級事故。

查詢優(yōu)化

此外,在使用 ORM 工具時,需要進(jìn)行查詢優(yōu)化,因?yàn)?ORM 只能根據(jù)輸入?yún)?shù)做一些簡單的優(yōu)化處理,而對于一些極限情況,需要開發(fā)人員自己去注意。例如,在進(jìn)行 SQL 查詢用 in 時,由于條件長度較長,可能會因?yàn)閿?shù)據(jù)庫引擎的原因?qū)е?SQL 無法執(zhí)行或執(zhí)行效率較低,此時需要將查詢條件進(jìn)行分組,利用 Node.js 進(jìn)行分批查詢,并在內(nèi)存中組裝結(jié)果。

在 ORM 的使用中,需要注意不正確使用 ORM 的 API 調(diào)用可能會導(dǎo)致生成子查詢,從而降低查詢性能。

最后

最后,推薦大家閱讀 ORM 的源碼(https://leoric.js.org/)和《企業(yè)應(yīng)用架構(gòu)模式》(https://martinfowler.com/eaaCatalog/index.html),尤其是其中介紹的兩種架構(gòu)模式。


低代碼是當(dāng)今最熱門的技術(shù)之一,如果你對低代碼感興趣,或者正在研究低代碼,歡迎報名第 63 屆早早聊大會 - 低代碼無代碼,跟早早聊一起,玩轉(zhuǎn)低代碼。

  • 舉辦時間:2023 年 4 月 15 日 ?10:00 ~ 17:00

  • 截至?xí)r間:2023 年 4 月 15 日 ?19:00

  • 舉辦方式:微信群 PPT 推送 + 線上視頻實(shí)時直播 + 會后資料推送

  • 報名方式:https://www.zaozao.run/conf/c63

  • 大會主辦方:前端早早聊


【前端大佬 | Node 連載 2/9】語雀團(tuán)隊(duì) - 小琿:《Node.js ORM 在語雀的探索與實(shí)踐》的評論 (共 條)

分享到微博請遵守國家法律
长春市| 宣恩县| 彭山县| 什邡市| 罗山县| 轮台县| 浮梁县| 黄陵县| 余庆县| 彩票| 射洪县| 土默特左旗| 齐河县| 贵州省| 托克托县| 琼中| 杨浦区| 郎溪县| 固原市| 山阴县| 虹口区| 修武县| 凌云县| 手游| 无为县| 蒙山县| 郑州市| 瑞安市| 佛冈县| 丰都县| 金华市| 尉氏县| 海宁市| 手机| 耒阳市| 大同市| 太仆寺旗| 庐江县| 丹寨县| 高平市| 密山市|