我們要不要使用 ORM?
ORM 他是個啥?
一提到 ORM 很多同學(xué)知道他是跟數(shù)據(jù)庫相關(guān)的一個內(nèi)容,但是并不清楚他到底是這個啥,自己需不需要,到底怎么玩?
實際上 ORM 就那么一回事,從這三個字母就可以看到
O:Object
R:Relational
M:Mapping
對象關(guān)系映射,即關(guān)系型數(shù)據(jù)庫和我們的實體業(yè)務(wù)對象來進(jìn)行一個映射,對與我們使用 ORM 對象來說,就直接去使用其對應(yīng)的各種方法即達(dá)到自動持久化的目的,無需關(guān)注具體的 sql 細(xì)節(jié)
因為 ORM 已經(jīng)為你隱藏了關(guān)于 sql 的部分,讓不熟悉 sql 的 xdm 也可以很好的上手
只要你知道如何使用函數(shù),使用對象里面的方法到底你的數(shù)據(jù)操作目的即可
為什么要用 ORM?
為什么要使用 ORM 呢?難道出了一個新的東西,我們就一定要用嗎?自然是要知道他的好,我們才會去使用
結(jié)論先放在前面,使用 ORM
- 可以減少我們重復(fù)的寫垃圾代碼,可以提高我們的工作效率,降低開發(fā)成本
- 訪問數(shù)據(jù)的時候,可以使用抽象的方式,用起來非常簡潔
- 以及 orm 帶來的各種奇淫巧技
舉一個 gorm 的例子
在 GO 中我們訪問 mysql 關(guān)系型數(shù)據(jù)庫,數(shù)據(jù)庫中提前先創(chuàng)建好了數(shù)據(jù)庫,數(shù)據(jù)表,以及 3 條記錄
圖片
GO 中有給我們提供對應(yīng)的庫
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
我們可以使用 sql.Open() 連接 mysql 數(shù)據(jù)庫
func Connect() (*sql.DB, error) {
db, err := sql.Open("mysql", "root:123456@/test_gorm")
if err != nil {
return nil, err
}
return db, nil
}
獲取到 db 句柄之后,我們可以通過這樣的方式,輸入 sql 語句來查詢數(shù)據(jù)
圖片
可以發(fā)現(xiàn),本次的查詢語句是 select id,name,email,member_number,address from users where id = ? ,我們再一條數(shù)據(jù)一條數(shù)據(jù)的讀取出來(此處需要注意使用讀取 rows.Next() 的時候,需要讀取完畢之后,關(guān)閉句柄,否則會資源泄漏)
圖片
那么如果我們換成別的查詢語句,或者其他增刪改的語句呢?
回顧一下以前各種瘋狂寫重復(fù)代碼 sql 代碼的情況,流程是一樣的,代碼結(jié)構(gòu)也是類似的,寫著差不多的代碼,過著差不多的人生嗎?
甚至這一塊的代碼很多或許都是復(fù)制粘貼,然后改改 sql,改改響應(yīng)結(jié)果
這也太無聊和重復(fù)了,咱們還真的是個碼農(nóng)了?別人搬磚,我們搬代碼?
這不,這個時候,我們就可以使用 ORM 來幫助我們提高生產(chǎn)效率, 減少我們的低價值重復(fù)勞動,可以留更多的時間來進(jìn)行思考和優(yōu)化
這樣,我們使用 gorm 的話,連接數(shù)據(jù)我們就可以這樣來寫
func Connect(user, pwd, ip, port string) (*gorm.DB, error) {
db, err := gorm.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/test_gorm?charset=utf8&parseTime=True&loc=Local", user, pwd, ip, port))
if err != nil {
return nil, err
}
return db, nil
}
上述的查詢就會變成這樣的
圖片
有沒有發(fā)現(xiàn),對應(yīng)的地方,使用 orm 的方式,對于咱們來說,其實就是需要查詢一條數(shù)據(jù),完全都不需要去關(guān)心 sql ,只需要按照對象去應(yīng)用方法就可以查詢我們想要的數(shù)據(jù)
圖片
看到這里,有沒有初步覺得 ORM 還是很香的,至少咱們寫數(shù)據(jù)持久化的時候,就不需要寫那么多重復(fù)代碼了,使用 ORM 方便高效
gorm 簡述和提醒
看了上述例子是否會有這些疑問,
- Import 包的時候為什么導(dǎo)入了又不用?
- 為什么連接數(shù)據(jù)庫的時候需要帶上 mysql 字符串?
import _ "github.com/go-sql-driver/mysql"
首先,一個庫如果不用的話,那當(dāng)然是沒有必要導(dǎo)入的,導(dǎo)入了正式因為需要使用
可以看到 mysql 包中的 init 函數(shù),實際上就是做一個注冊,用一個有效的名字,對一個這一個數(shù)據(jù)庫引擎
func init() {
sql.Register("mysql", &MySQLDriver{})
}
Register 實現(xiàn)如下
圖片
可以看到在sql包里面有一個全局map,里把存放了mysql這個名字的driver
圖片
再來查看 gorm.Open() 的實現(xiàn)就一目了然了
gorm.Open 中調(diào)用了 sql.Open , sql.Open 中去從全局的 map driver中獲取 mysql 字符串對應(yīng)的引擎
gorm.Open
圖片
sql.Open
圖片
這一塊就到這里,如果需要系統(tǒng)的學(xué)習(xí)和了解 gorm,可以從這里進(jìn)入:
- https://www.topgoer.cn/docs/gorm/gorm-1c54sbcda16o6
- https://gorm.io/
- gorm.Open 為什么要帶上 charset=utf8&parseTime=True&loc=Local
其中 charset 是表示字符編碼
parseTime 為 True ,表示處理數(shù)據(jù)的時候,會去解析時間
loc=Local 表示入庫的時候,使用的是本地時區(qū)
以及 gorm 有沒有其他的坑?
實際上在應(yīng)用 gorm 的時候,還是會有很多坑等著咱們,此處先給大家避避坑
與其說是坑,實際上還是自己去應(yīng)用一個技術(shù)的時候?qū)ζ洳粔蛄私猓J(rèn)知沒有對齊導(dǎo)致的
- 創(chuàng)建數(shù)據(jù)表的坑
使用 gorm 創(chuàng)建數(shù)據(jù)表的時候,會先要定義一個基本的數(shù)據(jù)模型,表示數(shù)據(jù)表中有哪些字段,其中 gorm 默認(rèn)給我們提供了一些默認(rèn) model,根據(jù)實際情況使用即可
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time `sql:"index"`
}
例如我們子定義的表結(jié)構(gòu)是這樣的:
圖片
創(chuàng)建出來的表格名為 users ,我們可以使用如下語句禁用表名復(fù)數(shù),或者自定義一個表名都是可以的
db.SingularTable(true)
- 解析時間的坑
上述使用 gorm.Open() 連接數(shù)據(jù)庫的時候,咱們指定了 parseTime=True ,那么后續(xù)處理時間類型的數(shù)據(jù)就不會有問題,如果不指定的話,gorm 處理時間類型的數(shù)據(jù)會處理出錯
- 想當(dāng)然的坑
ORM 固然用起來方便,不動 sql 的人用起來也很爽,但是一些基本的操作還是要注意的,否則會對性能影響非常大
例如,查詢一批數(shù)據(jù)的時候獲取會想當(dāng)然的這樣來寫
// 偽代碼,示意一波
userList:=[]int{1, 3, 5}
user := dao.User{}
for _,v := range userList {
db.First(&user, v)
}
或許在寫其他邏輯的時候這樣寫好像沒啥問題,但是你要明白現(xiàn)在是操作數(shù)據(jù)庫,怎么可以循環(huán)操作數(shù)據(jù)庫呢?如果 demo 中的 userList 足夠的大,那么結(jié)果可想而知
在 gorm 完全可以使用 where 的方式來達(dá)到我們的查詢目的,還是需要我們理解了之后,靈活使用,不要生搬硬套,例如
users := make([]dao.User, 0)
db.Where("id in (?)", []int{1, 2, 3}).Find(&users)
ORM 給我們帶來了哪些問題?
Xdm 閉著眼睛想一下,原來是直接就使用 sql 去操作數(shù)據(jù)庫的,現(xiàn)在咱們通過了一層 gorm 對象,自然是會對我們的性能帶來影響的,而且 ORM 是多層系統(tǒng)的
- ORM 里面需要去管理多個關(guān)聯(lián)和映射,需要消耗資源
- 需要咱們學(xué)習(xí)新知識,增加學(xué)習(xí)成本
- 會產(chǎn)生依賴,長期不用 sql,慢慢的可能你就不會完整的 sql 了
- 稍不注意可能就會寫出低性能的代碼
- ... 等等,歡迎補(bǔ)充
如何去考慮是否要使用 ORM?
那么我們知道了 ORM 的優(yōu)劣,那么我們是否要去選擇并使用它呢?
根據(jù)我們實際項目的需要來定,如果項目比較大,對性能要求較高,那么還是不要使用了
如果項目不大,并且有很多簡單的,重復(fù)的,低效的數(shù)據(jù)操作,那么還是可以使用的,使用起來確實非常方便,方便到讓你忘記 sql
總的來說,要還是不要,是個問題,如果是你,你會怎么選?