Go Web 編程--應用ORM

Go Web 編程--應用 ORM

上篇文章中咱們在使用的開發環境中增長了MySQL容器,而後介紹了使用database/sql標準庫結合數據庫驅動包進行數據庫操做的方法。不過它們是相對偏底層的軟件包。實際開發常常會使用一些在它的基礎上封裝的 ORM庫。ORM的查詢使用起來更簡單些,語法更富表達力。這篇文章咱們主要探究下面這些內容。mysql

  • gorm的基本用法
  • 如何管理ORM的使用
  • 如何合理規劃項目目錄結構

安裝gorm包

gorm是一個出色的,對開發人員友好的 Golang ORM 庫,其支持的特性包括:git

  • 全特性 ORM (幾乎包含全部特性)
  • 模型關聯 (一對一, 一對多,一對多(反向), 多對多, 多態關聯)
  • 鉤子 (Before/After Create/Save/Update/Delete/Find)
  • 預加載
  • 事務
  • 複合主鍵
  • SQL 構造器
  • 自動遷移
  • 日誌

使用以下命令進行安裝:github

go get -u github.com/jinzhu/gorm
複製代碼

將gorm加入項目中

規劃數據模型目錄結構

咱們在項目根目錄下新建以下目錄:web

http_demo
|
└───model
│   └───dao
│   │   init.go
│   └───────table
│           │   user.go
複製代碼

在 Go 中包以目錄的形式來組織,因此model包中存放全部數據模型,dao表明數據訪問對象,存放數據庫CRUD方法的封裝,其中的init.go存放dao包的初始化函數主要是用來在加載包後鏈接上數據庫。table包裏放與數據表對應的模型定義(使用 ORM 以前要先定義模型與數據庫中的表對應),在示例裏咱們會定義一個User模型放在user.go文件中。sql

規劃完目錄後就能夠在各部分寫相應的代碼了,首先來看使用gorm鏈接數據庫。docker

鏈接數據庫

咱們在dao包的init.go中加入包的初始化邏輯進行數據庫鏈接,初始化函數會在dao包第一次被導入時執行,因爲gorm文檔鏈接數據庫的例子太簡單,參考價值不大,咱們根據項目須要作些簡單封裝,init.go中的代碼以下所示:shell

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,在運行了Goapp容器須要用服務名訪問容器網絡中的其餘容器。關於容器環境的詳細配置請你們查看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包,把邏輯放在這一層。這樣對代碼的管理、複用性都有幫助。bash

由於數據庫的 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獲取文章中完整的源代碼,喜歡個人文章請點贊和收藏。

前文回顧

深刻學習用Go編寫HTTP服務器

Web服務器路由

用Docker快速搭建Go開發環境

十分鐘學會用Go編寫Web中間件

Go Web編程--應用數據庫

Go Web編程--應用ORM
相關文章
相關標籤/搜索