GORM 在項(xiàng)目中的初始化、重要連接參數(shù)和多數(shù)據(jù)源配置
GORM的下載與安裝
首先GORM 升級(jí)到 V2 以后項(xiàng)目組織發(fā)生了變更從 github.com/jinzhu/gorm 變成了 gorm.io/gorm 安裝步驟也會(huì)跟之前的V1版本有些不同
我們先來安裝GORM,邊安裝邊說。
go get -u gorm.io/gorm
GORM 在V1 版本中各個(gè)數(shù)據(jù)庫的驅(qū)動(dòng)是和整個(gè)軟件包綁定在一起的,所以下載安裝一次就行了,但是到了V2之后每種數(shù)據(jù)庫單獨(dú)提供了驅(qū)動(dòng),我們使用的是MySQL,所以先把MySQL的驅(qū)動(dòng)安裝一下
go get -u "gorm.io/driver/mysql"
如果你的數(shù)據(jù)庫里用了多數(shù)據(jù)源,那么你需要把項(xiàng)目用到的每個(gè)數(shù)據(jù)庫類型的驅(qū)動(dòng)都先安裝上,假如說項(xiàng)目中還使用了 postgres 那么在初始化GORM前也需要把 postgres 的驅(qū)動(dòng)下載下來。
go get -u "gorm.io/driver/postgres"
之所以安裝這個(gè)驅(qū)動(dòng)呢,是因?yàn)閮蓚€(gè)版本在初始化數(shù)據(jù)看連接時(shí)的Open 方法有了調(diào)整
// V1
func Open(dialect string, args ...interface{}) (db *DB, err error) {}
// V2
func Open(dialector Dialector, opts ...Option) (db *DB, err error) {}
V1 版本我們直接傳一個(gè)數(shù)據(jù)庫類型的字符串就行了
db, err := gorm.Open("mysql", "root:pass@tcp(xxx)/db_name")
if err != nil {
panic(err)
}
而V2版本需要用到我們剛才安裝的驅(qū)動(dòng)
db, err := gorm.Open(
mysql.Open("root:pass@tcp(xxx)/db_name),
&gorm.Config{},
)
初始化GORM
安裝完驅(qū)動(dòng)后先不著急去初始化GORM,前面的章節(jié)《Go 項(xiàng)目配置的定制化及一體化打包方案》我們給項(xiàng)目做好了配置管理,所以我們得先把配置文件進(jìn)行一些調(diào)整,打開我們的config/application.dev.yaml 文件,添加一些Database相關(guān)的配置
database:
type: mysql
master:
dsn: root:superpass@tcp(localhost:30306)/go_mall?xxx...
maxopen: 100
maxidle: 10
maxlifetime: 300000000000
slave:
dsn: root:superpass@tcp(localhost:30306)/go_mall?xxx...
maxopen: 100
maxidle: 10
maxlifetime: 300000000000
這里我們配置了主從兩個(gè)數(shù)據(jù)庫連接的配置,因?yàn)槲覀冺?xiàng)目里暫時(shí)用不到主從分離,所以就先把主庫和從庫設(shè)置的一樣,等實(shí)際開發(fā)用到主從實(shí)例了再去進(jìn)行相應(yīng)的修改。這里的參數(shù)等到下面初始化GORM的時(shí)候再去細(xì)講。
接下來我們?cè)?dal/dao/gorminit.go 中寫一個(gè)initDB的自定義函數(shù),把用Database配置來初始化GORM DB連接的這部操作抽象提煉到一起
func initDB(option config.DbConnectOption) *gorm.DB {
db, err := gorm.Open(mysql.Open(option.DSN), &gorm.Config{})
if err != nil {
panic(err)
}
sqlDb, _ := db.DB()
sqlDb.SetMaxOpenConns(option.MaxOpenConn)
sqlDb.SetMaxIdleConns(option.MaxIdleConn)
sqlDb.SetConnMaxLifetime(option.MaxLifeTime)
if err = sqlDb.Ping(); err != nil {
panic(err)
}
return db}
生產(chǎn)環(huán)境GORM必須設(shè)置的連接參數(shù)
GORM 使用的是Go的 database/sql 來維護(hù)的連接池,這里解釋一下創(chuàng)建GORM DB連接時(shí)用到的這些參數(shù),我們?cè)谂渲梦募镏付ǖ膍axidle、maxopen、maxlifetime 分別傳遞給了GORM DB的下面三個(gè)方法,這三個(gè)方法在生產(chǎn)環(huán)境時(shí)一定要記得設(shè)置
- SetMaxIdleConns(10) 設(shè)置最大空閑連接數(shù)為10個(gè)。
- SetMaxOpenConns(100) 設(shè)置可打開的最大連接數(shù)為 100 個(gè)。
- SetConnMaxLifetime 設(shè)置一個(gè)連接空閑后在多長(zhǎng)時(shí)間內(nèi)可復(fù)用,上面配置文件里設(shè)置的是300000000000, 因?yàn)镚o的time.Duration底層類型是int64, 一秒是1000000000,這個(gè)大家可設(shè)置一個(gè)適當(dāng)?shù)臅r(shí)間,一般5~15分鐘,不要太長(zhǎng)。
Open 方法的第二個(gè)參數(shù)我們傳遞了一個(gè) &gorm.Config{} ,里面沒有設(shè)置任何配置選項(xiàng)
db, err := gorm.Open(mysql.Open(option.DSN), &gorm.Config{})
我們暫時(shí)還用不到它,下一節(jié)當(dāng)我們需要把GORM日志整合到應(yīng)用日志時(shí)才會(huì)用到它。
讀寫分離和多數(shù)據(jù)源配置
讀寫分離
首先GORM V2 版本支持一個(gè)自動(dòng)按照?qǐng)?zhí)行的語句進(jìn)行讀寫分離連接切換的功能 DBResolver,但是感覺用起來還是比較麻煩。
這個(gè)大家可以自己研究一下,這里為介紹一個(gè)在GORM V1時(shí)就一直用的土辦法,這種方法雖然不支持自動(dòng)切換,但貴在簡(jiǎn)單,在寫Dao方法時(shí)根據(jù)邏輯類型選擇對(duì)應(yīng)的DB連接即可。
我們?cè)谠?dal/dao 的 gorminit.go 文件開頭定義好保存主庫和讀庫實(shí)例的變量
var _DbMaster *gorm.DB
var _DbSlave *gorm.DB
// DB 返回只讀實(shí)例
func DB() *gorm.DB {
return _DbSlave
}
// DBMaster 返回主庫實(shí)例
func DBMaster() *gorm.DB {
return _DbMaster
}
為每個(gè)變量提供了Getter方法,這樣使用起來代碼更簡(jiǎn)潔一些。初始化主庫和從庫的DB連接時(shí),在init方法中使用上面介紹過的initDB方法,用主從庫各自的配置進(jìn)行初始化。
在寫DAO方法時(shí)根據(jù)邏輯類型選擇對(duì)應(yīng)的DB連接使用。
多數(shù)據(jù)源配置
有的時(shí)候你的項(xiàng)目里的數(shù)據(jù)可能來自不同的數(shù)據(jù)庫,那么現(xiàn)在項(xiàng)目的配置和初始化方法還不支持多數(shù)據(jù)源。
一開始做項(xiàng)目的時(shí)候我確實(shí)沒有考慮到這個(gè)問題,工作中大部分DB用的也是MySQL,所以這里設(shè)計(jì)的不夠靈活,好在咱們讀者中已經(jīng)有人開始在項(xiàng)目中使用起來了,并且還做了多數(shù)據(jù)源的擴(kuò)展。