Go 數(shù)據(jù)存儲篇(七):GORM 使用入門

1、ORM 與 GORM
我們已經(jīng)成功存儲數(shù)據(jù)到數(shù)據(jù)表,但是所有操作都要自行編寫代碼,很多編程語言和框架會引入 ORM 來解決模型類與數(shù)據(jù)表記錄的映射關(guān)系,ORM 架起了 SQL 語句和應(yīng)用程序之間的橋梁,將模型類和數(shù)據(jù)表映射起來,將模型類字段和數(shù)據(jù)表字段建立關(guān)聯(lián)。
典型的 ORM 庫比如 Java 中的 Hibernate、Ruby 中的 ActiveRecord、以及 Laravel 中的 Eloquent。
在 Go 語言中,也有這樣的 ORM 庫,最流行的當(dāng)屬 GORM。
GORM 是一個適用于 Go 語言的 ORM 庫,遵循 ActiveRecord 模式進(jìn)行設(shè)計(jì)。
注:ORM 有兩種實(shí)現(xiàn)方式 —— ActiveRecord 和 DataMapper,關(guān)于兩者之間的區(qū)別可以參考這篇教程:https://xueyuanjun.com/post/966.html。
GORM 的功能非常強(qiáng)大,除了基本的基于模型類對數(shù)據(jù)表進(jìn)行增刪改查之外,還支持定義關(guān)聯(lián)關(guān)系、執(zhí)行數(shù)據(jù)表遷移、查詢鏈以及很多其他高級特性,并且支持在特定事件發(fā)生時(比如插入、更新、刪除)觸發(fā)指定的回調(diào)函數(shù)(類似 Laravel 框架的模型事件)。
下面我們來簡單演示下如何基于 GORM 進(jìn)行增刪改查和關(guān)聯(lián)查詢。
2、GORM 使用示例
使用之前需要先安裝 GORM:
go?get?github.com/jinzhu/gorm
然后我們編寫一段示例代碼:
package?main
import?(
????"fmt"
????"github.com/jinzhu/gorm"
????_?"github.com/jinzhu/gorm/dialects/mysql"
????"time"
)
type?Post?struct?{
????Id?int
????Title?string
????Content?string
????Author?string?`sql:"not?null"`
????CreatedAt?time.Time
????Comments?[]Comment
}
type?Comment?struct?{
????Id?int
????Content?string
????Author?string?`sql:"not?null"`
????PostId?int?`sql:"index"`
????CreatedAt?time.Time
}
var?DbConn?*gorm.DB
func?init()??{
????var?err?error
????DbConn,?err?=?gorm.Open("mysql",?"root:root@/test_db?charset=utf8mb4&parseTime=true")
????if?err?!=?nil?{
????????panic(err)
????}
????DbConn.AutoMigrate(&Post{},?&Comment{})
}
func?main()??{
????post?:=?Post{Title:?"GORM?示例教程",?Content:?"基于?GORM?進(jìn)行數(shù)據(jù)庫增刪改查",?Author:?"學(xué)院君"}
????//?通過?GORM?插入文章記錄
????DbConn.Create(&post)
????fmt.Println(post)
????//?通過關(guān)聯(lián)關(guān)系新增評論并將其附加到對應(yīng)的文章記錄
????comment?:=?Comment{Content:?"Test?Comment",?Author:?"學(xué)院君小號"}
????DbConn.Model(&post).Association("Comments").Append(comment)
????//?查詢文章記錄
????var?gormPost?Post
????DbConn.Where("author?=??",?"學(xué)院君").First(&gormPost)
????//?查詢包含評論數(shù)據(jù)的文章記錄
????var?comments?[]Comment
????DbConn.Model(&gormPost).Related(&comments)
????fmt.Println(comments[0])
}
由于 GORM 會根據(jù)模型類結(jié)構(gòu)體聲明自動創(chuàng)建對應(yīng)的數(shù)據(jù)表,所以我們可以刪除 test_db 數(shù)據(jù)庫中的 posts 和 comments 表,然后運(yùn)行這段代碼看看結(jié)果是否符合預(yù)期:

可以看到,數(shù)據(jù)表的插入和關(guān)聯(lián)查詢結(jié)果都是正常的。下面我們簡單分析下這段示例代碼。
3、GORM 運(yùn)行原理
數(shù)據(jù)庫連接
由于 GORM 也實(shí)現(xiàn)了 database/sql 接口,所以建立數(shù)據(jù)庫連接和之前使用 go-sql-driver/mysql 包類似,只是調(diào)用方法改成了 gorm.Open:
DbConn,?err?=?gorm.Open("mysql",?"root:root@/test_db?charset=utf8mb4&parseTime=true")
參數(shù)和之前完全一樣,引入的驅(qū)動包調(diào)整為 jinzhu/gorm 即可:
"github.com/jinzhu/gorm"
_?"github.com/jinzhu/gorm/dialects/mysql"
注:更多關(guān)于 GORM 數(shù)據(jù)庫連接配置的細(xì)節(jié),請參考 GORM 官方文檔(https://gorm.io/zh_CN/docs/)。
數(shù)據(jù)表自動遷移
和使用 go-sql-driver/mysql 包不同的是,這次我們不再需要手動創(chuàng)建數(shù)據(jù)表,因?yàn)?GORM 提供了數(shù)據(jù)表自動遷移功能:
DbConn.AutoMigrate(&Post{},?&Comment{})
通過 AutoMigrate 方法傳入要遷移的模型類實(shí)例即可,GORM 會自動創(chuàng)建對應(yīng)的數(shù)據(jù)表,表名規(guī)則是模型類名小寫的復(fù)數(shù)形式。
模型類定義
接下來,我們看下模型類的定義:
type?Post?struct?{
????Id?int
????Title?string
????Content?string
????Author?string?`sql:"not?null"`
????CreatedAt?time.Time
????Comments?[]Comment
}
type?Comment?struct?{
????Id?int
????Content?string
????Author?string?`sql:"not?null"`
????PostId?int?`sql:"index"`
????CreatedAt?time.Time
}
這里定義了兩個模型類,Post 和 Comment,分別對應(yīng)數(shù)據(jù)表 posts 和 comments,并且在 Post 中通過如下方式定義了 Post 和 Comment 之間的一對多關(guān)聯(lián):
Comments?[]Comment
這里我們沒有用結(jié)構(gòu)體標(biāo)簽指定關(guān)聯(lián)外鍵(GORM 支持通過結(jié)構(gòu)體標(biāo)簽設(shè)置數(shù)據(jù)表字段屬性),GORM 底層會自動維護(hù)這個關(guān)聯(lián),默認(rèn)規(guī)則是在 Comment 中的 PostId 字段(即當(dāng)前模型類名加上主鍵 ID 后綴)。
但是還是有一些字段設(shè)置了結(jié)構(gòu)體標(biāo)簽,這是為了給該字段添加額外的數(shù)據(jù)表字段約束,比如索引、是否允許為空等:
Author?string?`sql:"not?null"`
PostId?int?`sql:"index"`
注:更多模型類定義的細(xì)節(jié)和結(jié)構(gòu)體標(biāo)簽設(shè)置,請參考 GORM 官方文檔。
增刪改查
我們繼續(xù)來看增刪改查和關(guān)聯(lián)模型的操作,在 GORM 中,我們總算不用維護(hù) SQL 語句了,所有的增刪改查操作都可以通過 GORM 庫提供的方法來實(shí)現(xiàn),比如要創(chuàng)建一條記錄可以這么做:
post?:=?Post{Title:?"GORM?示例教程",?Content:?"基于?GORM?進(jìn)行數(shù)據(jù)庫增刪改查",?Author:?"學(xué)院君"}
DbConn.Create(&post)
模型類中的 Id 和 CreatedAt 字段系統(tǒng)會自動維護(hù),不需要顯示設(shè)置。
注:如果要實(shí)現(xiàn)修改、刪除和查詢操作,請參考 GORM 官方文檔 CRUD 接口部分,這些也都有相應(yīng)的內(nèi)置方法。
關(guān)聯(lián)查詢
如果要在上述模型實(shí)例上創(chuàng)建與之關(guān)聯(lián)的評論,可以這么做:
comment?:=?Comment{Content:?"Test?Comment",?Author:?"學(xué)院君小號"}
DbConn.Model(&post).Association("Comments").Append(comment)
最后要查詢包含關(guān)聯(lián)評論記錄的主題,可以這么做:
var?gormPost?Post
DbConn.Where("author?=??",?"學(xué)院君").First(&gormPost)
var?comments?[]Comment
DbConn.Model(&gormPost).Related(&comments)
注:更多關(guān)聯(lián)查詢和操作的使用,請參考 GORM 官方文檔的關(guān)聯(lián)部分。
4、小結(jié)
可以看到,引入 GROM 之后,我們不再需要手動編寫復(fù)雜的 SQL 語句,只需要借助 GORM 提供的方法就可以非常便捷地完成數(shù)據(jù)庫交互,這極大簡化了我們?nèi)粘i_發(fā)的代碼編寫和維護(hù)成本,也降低了安全風(fēng)險(xiǎn),所有的 SQL 語句都由 GORM 底層去構(gòu)建并執(zhí)行,它會將上層模型實(shí)例的增刪改查、關(guān)聯(lián)操作方法執(zhí)行轉(zhuǎn)化為相應(yīng)的 SQL 語句去執(zhí)行,這也是 ORM 的設(shè)計(jì)初衷。
以上只是 GORM 的簡單示例,完整功能請閱讀官方文檔(https://gorm.io/zh_CN/docs/),需要指出的是 GORM 的作者是中國人,所以中文文檔支持非常友好。
關(guān)于 Go 語言的數(shù)據(jù)庫操作部分,我們就簡單介紹到這里,到目前為止,還并沒有看到 Go 語言相對于 PHP 開發(fā) Web 應(yīng)用的任何優(yōu)勢,接下來,我們來看看 Go 語言 Web 編程的重頭戲 —— 并發(fā)編程,這也是 Go 語言本身的優(yōu)勢所在。
(全文完)
推薦閱讀

