上篇文章中我們在使用的開發環境中增加了MySQL
容器,然後介紹了使用database/sql
標準庫結合資料庫驅動包進行資料庫操作的方法。不過它們是相對偏底層的軟體包。實際開發經常會使用一些在它的基礎上封裝的 ORM
庫。ORM
的查詢使用起來更簡單些,語法更富表達力。這篇文章我們主要探究下面這些內容。
gorm
的基本用法- 如何管理
ORM
的使用 - 如何合理規劃專案目錄結構
安裝gorm包
gorm
是一個出色的,對開發人員友好的 Golang
ORM
庫,其支援的特性包括:
- 全特性 ORM (幾乎包含所有特性)
- 模型關聯 (一對一, 一對多,一對多(反向), 多對多, 多型關聯)
- 鉤子 (Before/After Create/Save/Update/Delete/Find)
- 預載入
- 事務
- 複合主鍵
- SQL 構造器
- 自動遷移
- 日誌
使用如下命令進行安裝:
go get -u github.com/jinzhu/gorm
將gorm加入專案中
規劃資料模型目錄結構
我們在專案根目錄下新建如下目錄:
http_demo
|
└───model
│ └───dao
│ │ init.go
│ └───────table
│ │ user.go
在 Go 中包以目錄的形式來組織,所以model
包中存放所有資料模型,dao
代表資料訪問物件,存放資料庫CRUD
方法的封裝,其中的init.go
存放dao
包的初始化函式主要是用來在載入包後連線上資料庫。table
包裡放與資料表對應的模型定義(使用 ORM 之前要先定義模型與資料庫中的表對應),在示例裡我們會定義一個User
模型放在user.go
檔案中。
規劃完目錄後就可以在各部分寫相應的程式碼了,首先來看使用gorm
連線資料庫。
連線資料庫
我們在dao
包的init.go
中加入包的初始化邏輯進行資料庫連線,初始化函式會在dao
包第一次被匯入時執行,由於gorm
文件連線資料庫的例子太簡單,參考價值不大,我們根據專案需要做些簡單封裝,init.go
中的程式碼如下所示:
package dao
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
"time"
)
var _DB *gorm.DB
func DB() *gorm.DB {
return _DB
}
func init() {
_DB = initDB()
}
func initDB() *gorm.DB {
// In our docker dev environment use
// db, err := gorm.Open("mysql", "go_web:go_web@tcp(database:3306)/go_web?charset=utf8&parseTime=True&loc=Local")
db, err := gorm.Open("mysql", "go_web:go_web@tcp(localhost:33063)/go_web?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
db.DB().SetMaxOpenConns(100)
db.DB().SetMaxIdleConns(10)
db.DB().SetConnMaxLifetime(time.Second * 300)
if err = db.DB().Ping(); err != nil {
panic(err)
}
return db
}
程式碼很簡單,大家實操的時候根據自己的MySQL
配置更改程式碼裡面的配置就行了。唯一說明一點的是,如果使用了我們提提供的Docker
環境,在連線資料庫時host
要改為database:3306
,因為我在容器環境裡將MySQL
容器的服務名定義成了database
,在執行了Go
的app
容器需要用服務名訪問容器網路中的其他容器。關於容器環境的詳細配置請大家檢視Go Web程式設計–應用資料庫 中的描述。
定義模型
使用模型訪問資料庫的表之前我們需要先定義對應的模型。我們示例中現在只有一個users
表,接下來我們在table
包中新增users
表的模型定義並放置在user.go
檔案中。
package table
import "time"
type User struct {
Id int64 `gorm:"column:id;primary_key"`
UserName string `gorm:"column:username"`
Secret string `gorm:"column:secret;type:varchar(1000)"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
// TableName sets the insert table name for this struct type
func (m *User) TableName() string {
return "users"
}
模型 CRUD
關於模型的 CRUD,建議將單個模型的CRUD
放在dao
包的單個檔案中,這樣方便以後程式碼的管理。這裡多說一點,建議不要直接用controller
或者叫handler
包直接訪問dao
包,而是在中間加一層logic
包,把邏輯放在這一層。這樣對程式碼的管理、複用性都有幫助。
因為資料庫的 CRUD 有很多種操作,本文的目的是幫助大家快速開始使用gorm
所以我就只放簡單的 CRUD 做演示了。大家按照這裡步驟引入gorm
後用到其他的資料庫操作了直接去官方文件裡查一查就好。
在dao
包中新建user.go
用來存放User
模型的操作方法。
package dao
import "example.com/http_demo/model/dao/table"
func CreateUser(user *table.User) (err error) {
err = DB().Create(user).Error
return
}
func GetUserById(userId int64) (user *table.User, err error) {
user = new(table.User)
err = DB().Where("id = ?", userId).First(user).Error
return
}
func GetAllUser() (users []*table.User, err error) {
err = DB().Find(&users).Error
return
}
func UpdateUserNameById(userName string, userId int64) (err error) {
user := new(table.User)
err = DB().Where("id = ?", userId).First(user).Error
if err != nil {
return
}
user.UserName = userName
err = DB().Save(user).Error
return
}
func DeleteUserById(userId int64) (err error) {
user := new(table.User)
err = DB().Where("id = ?", userId).First(user).Error
if err != nil {
return
}
err = DB().Delete(user).Error
return
}
驗證ORM 方法
經過上面幾步的設定後我們就可以在專案裡使用gorm
訪問資料庫了,由於我們專案的main goroutine
中執行了http
服務,所以我們使用測試用例對上面dao
包中定義的幾個方法進行一下測試。
篇幅原因我就只貼一個GetAllUsers
方法的測試用例了:
func TestGetAllUser(t *testing.T) {
tests := []struct {
name string
wantErr bool
}{
{
name: "test",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotUsers, err := GetAllUser()
if (err != nil) != tt.wantErr {
t.Errorf("GetAllUser() error = %v, wantErr %v", err, tt.wantErr)
return
}
for _, user := range gotUsers {
log.Info("user: %v", user)
}
})
}
}
執行測試後,可以看到結果:
INFO user: &{1 2020-02-15 14:14:46 +0800 CST 2020-02-15 06:44:17 +0800 CST}
--- PASS: TestGetAllUsers (0.00s)
--- PASS: TestGetAllUsers/test (0.00s)
PASS
Process finished with exit code 0
關注文末的公眾號回覆gohttp05
可以得到完整的測試用例程式碼,建議這些CRUD
都要寫好測試用例進行自測,使用GoLand
可以很容易的生成測試函式和執行測試。
重新規劃專案目錄
引入ORM
後,我們專案中的程式碼就比較多了,都放在根目錄下的main
包中有點雜亂,所以我們根據各部分的功能和職責對專案目錄進行了簡單的劃分,劃分後的目錄結構如下:
http_demo
|
└───handler//route handler
|
└───logic//business logic
|
└───middleware
│
└───model
│ └───dao
│ │ init.go
│ └───table
│ │ user.go
└───router// router
|
| main.go
感覺今天的內容還是挺多的,尤其對於剛入門Go
的同學們一定要把今天的程式碼下載下來實操一遍才能掌握。gorm
提供的功能還是很多的,每個功能在官方文件裡都有講解,我們這裡就不做過多介紹了。這篇文章的目的主要是讓大家能快速入門,同時把ORM
相關的程式碼管理和初始化流程做的規範些,這些組織方式完全可以應用到生產級別的專案中的。
關注文末的公眾號回覆
gohttp05
獲取文章中完整的原始碼,喜歡我的文章請點贊和收藏。
前文回顧
本作品採用《CC 協議》,轉載必須註明作者和本文連結