GoFrame DAO對象封裝設(shè)計(jì)-痛點(diǎn)及改進(jìn)

2022-03-29 15:46 更新

關(guān)于?DAO?數(shù)據(jù)訪問對象設(shè)計(jì)其實(shí)是關(guān)于?GoFrame?框架工程化實(shí)踐中比較重要一塊設(shè)計(jì)。

?DAO?設(shè)計(jì)結(jié)合?GoFrame?的?ORM?組件性能和易用性都很強(qiáng),可以極大提高開發(fā)和維護(hù)效率??赐瓯菊鹿?jié)內(nèi)容之后,小伙伴們應(yīng)該能夠理解并體會到使用?DAO?數(shù)據(jù)庫訪問對象設(shè)計(jì)的優(yōu)點(diǎn)。

一、現(xiàn)有ORM使用示例

1、需要定義模型

image2021-3-10_16-8-53

用戶基礎(chǔ)表(僅作演示,真實(shí)的表有數(shù)十個(gè)字段)

image2021-3-10_16-9-48

醫(yī)生信息表(僅作演示,真實(shí)的表有上百個(gè)字段)

2、GRPC接口實(shí)現(xiàn)示例

一個(gè)簡單的?GRPC?查詢信息接口。

image2021-3-10_16-13-22

一個(gè)簡單的?GRPC?數(shù)據(jù)查詢接口

二、現(xiàn)有痛點(diǎn)描述

1、必須要定義tag關(guān)聯(lián)表結(jié)構(gòu)與struct屬性,無法做到自動映射

表字段與實(shí)體對象屬性名稱之間原本就有一定的關(guān)聯(lián)規(guī)則,沒有必要定義和維護(hù)大量的?tag?定義。

image2021-3-10_17-9-45

大量非必要的?tag?定義,用于指定數(shù)據(jù)表字段到實(shí)體對象屬性映射

2、不支持通過返回對象指定需要查詢的字段

無法通過返回的對象數(shù)據(jù)結(jié)構(gòu)指定查詢字段,要么只能?SELECT *? ,要么只能通過額外的方法手動錄入查詢字段,效率很低下。

image2020-12-3_13-34-19

常見的SELECT *操作,無法根據(jù)接口對象指定查詢字段

3、無法對輸入對象屬性名稱進(jìn)行自動字段過濾

定義了輸入與輸出數(shù)據(jù)結(jié)構(gòu),輸出的數(shù)據(jù)結(jié)構(gòu)已經(jīng)包含我們需要查詢的字段名稱。開發(fā)者輸入定義的返回對象,期望在查詢的時(shí)候僅查詢我需要的字段名稱,多余的屬性則不會執(zhí)行查詢,自動過濾掉。

4、需要創(chuàng)建中間查詢結(jié)果對象執(zhí)行賦值轉(zhuǎn)換

查詢結(jié)果不支持?struct?智能轉(zhuǎn)換,需要額外定義一個(gè)中間?model?模型,再通過其他工具進(jìn)行復(fù)制,效率低。

image2021-3-10_18-5-30

存在中間臨時(shí)的模型對象,用于承接查詢結(jié)果及返回結(jié)構(gòu)對象賦值轉(zhuǎn)換

5、需要提前初始化返回對象,不管有無查詢到數(shù)據(jù)

這種方式不僅不優(yōu)雅,對性能也有影響,還對?GC?不太友好。期望查詢到數(shù)據(jù)時(shí)再自動創(chuàng)建返回對象,沒有查詢到數(shù)據(jù)時(shí)什么都不要做。

image2020-12-3_11-44-42

需要預(yù)先初始化返回對象,不管有無查詢到數(shù)據(jù)

6、通篇使用底層裸DB對象操作,沒有DAO對象封裝操作

大部分的Golang初學(xué)者似乎都傾向于使用一個(gè)全局的?DB?對象,在查詢的時(shí)候通過?DB?對象生成特定表的?Model?對象再執(zhí)行?CURD?操作,這是一種面向過程的使用方式。這種方式并沒有代碼分層的設(shè)計(jì)可言,使得數(shù)據(jù)操作和業(yè)務(wù)邏輯高度耦合。

image2020-12-3_11-47-1

原始數(shù)據(jù)庫對象操作方式,沒有?DAO?封裝

7、隨處可見的字符串硬編碼,如表名和字段的硬編碼

舉個(gè)例子,?userId?這個(gè)字段假如一不小心寫成了?UserId?或者?userid?,測試的時(shí)候如果沒有完全覆蓋到,在一定的條件下才觸發(fā)查詢操作,是不是會造成新的一場事故呢?

image2021-3-10_17-40-40

大量的字符串硬編碼

8、底層ORM引起太多的指針屬性定義

指針屬性對象為業(yè)務(wù)邏輯處理埋下隱患,開發(fā)者在代碼邏輯中需要在指針與屬性之間來回切換,特別是一些基礎(chǔ)類型往往需要通過重新取值的方式傳遞參數(shù)。如果輸入?yún)?shù)是?interface{}?類型,那么更容易引起?BUG?

image2022-1-13_23-29-3

?BUG?示例,指針屬性使用不當(dāng),引起地址比較邏輯錯(cuò)誤。

image2022-1-13_23-29-50

同時(shí)也影響了業(yè)務(wù)模型結(jié)構(gòu)體定義設(shè)計(jì),對開發(fā)者造成了錯(cuò)誤習(xí)慣引導(dǎo)(上層業(yè)務(wù)模型的指針屬性往往是為了迎合底層數(shù)據(jù)表實(shí)體對象,方便數(shù)據(jù)傳遞)。

image2022-1-13_23-31-46

值得注意一個(gè)常見錯(cuò)誤,就是將底層數(shù)據(jù)實(shí)體模型當(dāng)做頂層業(yè)務(wù)模型使用。特別是在底層數(shù)據(jù)實(shí)體對象使用指針屬性的場景下,該問題十分明顯。

9、可觀測性的支持:Tracing、Metrics、Logging

數(shù)據(jù)庫?ORM?作為業(yè)務(wù)項(xiàng)目最關(guān)鍵核心的組件,可觀測性的支持至關(guān)重要。但是大多數(shù)被認(rèn)為奉承所謂做得越少越"專業(yè)"的?ORM?組件卻不曾深諳此道。

10、數(shù)據(jù)集合與代碼數(shù)據(jù)實(shí)體結(jié)構(gòu)不一致

當(dāng)通過人工維護(hù)數(shù)據(jù)實(shí)體結(jié)構(gòu)時(shí),數(shù)據(jù)集合與代碼數(shù)據(jù)實(shí)體結(jié)構(gòu)往往會出現(xiàn)不一致的風(fēng)險(xiǎn),開發(fā)和維護(hù)成本高。

三、改進(jìn)方案設(shè)計(jì)

1、查詢結(jié)果對象無需特殊標(biāo)簽定義,全自動關(guān)聯(lián)映射

2、支持根據(jù)指定對象自動識別查詢字段,而不是全部?SELECT * ?

3、支持根據(jù)指定對象自動過濾不存在的字段內(nèi)容

4、使用?DAO?對象封裝代碼設(shè)計(jì),通過對象方式操作數(shù)據(jù)表

5、?DAO?對象將關(guān)聯(lián)的表名及字段名進(jìn)行封裝,避免字符串硬編碼

6、無需提前定義實(shí)體對象接受返回結(jié)果,無需創(chuàng)建中間實(shí)體對象用于接口返回對象的賦值轉(zhuǎn)換

7、查詢結(jié)果對象無需提前初始化,查詢到數(shù)據(jù)時(shí)才會自動創(chuàng)建

8、內(nèi)置支持?OpenTelemetry?標(biāo)準(zhǔn),實(shí)現(xiàn)可觀測性,極大提高維護(hù)效率、降低成本

9、支持?SQL?日志輸出能力,支持開關(guān)功能

10、數(shù)據(jù)模型、數(shù)據(jù)操作、業(yè)務(wù)邏輯解耦,支持?Dao?及?Model?代碼工具化自動生成,保證數(shù)據(jù)集合與代碼數(shù)據(jù)結(jié)構(gòu)一致,提高開發(fā)效率,便于規(guī)范落地

11、等等。

image2021-3-10_18-47-5

采用?DAO?設(shè)計(jì)改進(jìn)后的代碼示例


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號