1. 程式人生 > 程式設計 >Go元件學習——gorm四步帶你搞定DB增刪改查

Go元件學習——gorm四步帶你搞定DB增刪改查

1、簡介

ORM

Object-Relationl Mapping, 它的作用是對映資料庫和物件之間的關係,方便我們在實現資料庫操作的時候不用去寫複雜的sql語句,把對資料庫的操作上升到對於物件的操作。

gorm

gorm就是基於Go語言實現的ORM庫。

類似於Java生態裡大家聽到過的Mybatis、Hibernate、SpringData等。

Github

github.com/jinzhu/gorm

官方檔案

gorm.io/

2、如何使用Gorm

只要四步就能上手gorm,可以盡情的沉浸在毫無技術含量的CRUD世界。

2.1 下載gorm庫

下載gorm庫

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

這是比較原始的方式,現在有了go mod,我們可以更方便的配置,甚至不用配置。

寫好程式碼,在檔案下執行go build,go.mod會自動新增對於gorm的依賴包

github.com/jinzhu/gorm v1.9.10
複製程式碼

當然,也可以手動新增這個依賴。

具體參見go-demo專案https://github.com/DMinerJackie/go-demo

2.2 建立DB連線

建立資料庫連線

package main

import (
  "github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main
()
{ var err error db,connErr := gorm.Open("mysql","root:rootroot@/dqm?charset=utf8&parseTime=True&loc=Local") if connErr != nil { panic("failed to connect database") } defer db.Close() db.SingularTable(true) } 複製程式碼

gorm支援很多資料來源包括PostgreSQL、MySQL等。

這裡連線的是MySQL,所以需要引用"github.com/jinzhu/gorm/dialects/mysql"驅動。

通過上面宣告,已經獲取資料庫的連線。

db.SingularTable(true)這句的作用後面會提到。

2.3 建立對映表結構的struct

定義資料庫表結構對應的struct

比如這裡我們要操作的是表test表,表結構如下

CREATE TABLE `test` (
  `id` bigint(20) NOT NULL,`name` varchar(5) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
複製程式碼

於是我們對應可以定義struct結構如下

type Test struct {
	ID   int64  `gorm:"type:bigint(20);column:id;primary_key"`
	Name string `gorm:"type:varchar(5);column:name"`
	Age  int    `gorm:"type:int(11);column:age"`
}
複製程式碼

每個欄位後面的gorm是結構標記,可以用於宣告對應資料庫欄位的屬性。

比如ID後面的約束為該欄位為bigint(20)型別,對應列表為id,且該欄位為主鍵。

除此以外,還有更加豐富的標籤定義參見官方檔案:gorm.io/zh_CN/docs/…

2.4 CRUD

有了前面三步的鋪墊,下面就可以執行真正寫資料庫操作了。

比如"增"

test := &Test{
		ID:3,Name:"jackie",Age:18,}
	db.Create(test)
複製程式碼

比如"刪"

test := &Test{
		ID:3,}
db.Delete(test)
複製程式碼

比如"改"

test := &Test{
		ID:   3,Name: "hello",Age:  18,}
db.Model(&test).Update("name","world")
複製程式碼

比如"查"

var testResult Test
db.Where("name = ?","hello").First(&testResult)
fmt.Println("result: ",testResult)
複製程式碼

如果只是想做個純粹的CRUDer,掌握上面四步就算是會用gorm了。

如果還想來點花式的,更深入的,繼續往下看~~~

3、表名和結構體如何對映

從上面四步,我們只看到在建立DB連結的時候,提供的資訊僅僅到資料庫,那麼gorm是如何做到將表結構和你定義的struct對映起來的呢?

有三種方式可以實現,如果以下三種方式都沒有實現,如果你是建立表,則gorm預設會在你定義的struct名後面加上”s“,比如上面就會建立tests表。

3.1 db.SingularTable(true)

通過db.SingularTable(true),gorm會在建立表的時候去掉”s“的字尾

3.2 實現TableName方法

func (Test) TableName() string {
	return "test"
}
複製程式碼

TableName方法定義在scope.go的tabler介面中

type tabler interface {
	TableName() string
}
複製程式碼

3.3 通過Table API宣告

db.Table("test").Where("name = ?","hello").First(&testResult)
複製程式碼

在CRUD前,指明需要操作的表名也是OK的。

4、其他花式操作

下面花式API操作使用表dqm_user_role,對應struct如下

type DqmUserRole struct {
	ID        int64     `gorm:"column:id;primary_key" json:"id"`
	UserId    string    `gorm:"column:user_id" json:"user_id"`
	RoleId    string    `gorm:"column:role_id" json:"role_id"`
	CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
	UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
}
複製程式碼

表中初始資料如下 20190804-1-初始資料.png

以下API均親測可用

First

var dqmUserRole DqmUserRole
// 按照主鍵順序的第一條記錄
db.First(&dqmUserRole)
fmt.Println("roleId: ",dqmUserRole.RoleId)
複製程式碼

Last

var dqmUserRole1 DqmUserRole
// 按照主鍵順序的最後一條記錄
db.Last(&dqmUserRole1)
fmt.Println("roleId: ",dqmUserRole1.RoleId)
複製程式碼

Find

var dqmUserRoels []DqmUserRole
// 所有記錄
db.Find(&dqmUserRoels)
fmt.Println("dqmUserRoles: ",dqmUserRoels)
複製程式碼

Where

var dqmUserRole3 DqmUserRole
// 根據條件查詢得到滿足條件的第一條記錄
db.Where("role_id = ?","2").First(&dqmUserRole3)
fmt.Println("where roleId: ",dqmUserRole3.RoleId)

var dqmUserRoles4 []DqmUserRole
// 根據條件查詢得到滿足條件的所有記錄
db.Where("user_id = ?","1").Find(&dqmUserRoles4)
fmt.Println("where dqmUserRoles: ",dqmUserRoles4)

var dqmUserRole5 []DqmUserRole
// like模糊查詢
db.Where("role_id like ?","%2").Find(&dqmUserRole5)
fmt.Println("where dqmUserRoles: ",dqmUserRole5)

var dqmUserRole6 []DqmUserRole
db.Where("updated_at > ?","2019-02-08 18:08:27").Find(&dqmUserRole6)
fmt.Println("where dqmUserRoles: ",dqmUserRole6)

var dqmUserRole7 DqmUserRole
// struct結構查詢條件
db.Where(&DqmUserRole{RoleId: "1,2",UserId: "1"}).First(&dqmUserRole7)
fmt.Println("where dqmUserRole: ",dqmUserRole7)

var dqmUserRole8 DqmUserRole
// map結構查詢條件
db.Where(map[string]interface{}{"role_id": "1,"user_id": "1"}).Find(&dqmUserRole8)
fmt.Println("where dqmUserRole: ",dqmUserRole8)
複製程式碼

Not

var dqmUserRole9 DqmUserRole
db.Not([]int64{1}).First(&dqmUserRole9)
fmt.Println("not dqmUserRole: ",dqmUserRole9)
複製程式碼

Or

var dqmUserRole10 []DqmUserRole
db.Where(&DqmUserRole{RoleId: "1,2"}).Or(map[string]interface{}{"user_id": "2"}).Find(&dqmUserRole10)
fmt.Println("or dqmUserRoles: ",dqmUserRole10)
複製程式碼

FirstOrInit和Attrs

var dqmUserRole11 DqmUserRole
// 查不到該條記錄,則使用attrs值替換
db.Where("user_id = ?","0").Attrs("role_id","12").FirstOrInit(&dqmUserRole11)
fmt.Println("after FirstOrInit: ",dqmUserRole11)

var dqmUserRole12 DqmUserRole
// 查到記錄,則使用資料庫中的值
db.Where("user_id = ?","1").Attrs("role_id","2").FirstOrInit(&dqmUserRole12)
fmt.Println("after FirstOrInit: ",dqmUserRole12)
複製程式碼

FirstOrInit和Assign

var dqmUserRole13 DqmUserRole
// 不管是否找到對應記錄,使用Assign值替代查詢到的值
db.Where("role_id = ?","1,2").Assign(DqmUserRole{UserId: "15"}).FirstOrInit(&dqmUserRole13)
fmt.Println("assign dqmUserRole: ",dqmUserRole13)
複製程式碼

FirstOrCreate

var dqmUserRole14 DqmUserRole
// 如果記錄存在則返回結果,如果不存在則建立
db.Where(&DqmUserRole{UserId: "3",RoleId: "3"}).FirstOrCreate(&dqmUserRole14)
fmt.Println("firstOrCreate dqmUserRole: ",dqmUserRole14)
複製程式碼

Order

var dqmUserRole16 []DqmUserRole
db.Order("user_id desc").Find(&dqmUserRole16) // 注意這裡的order要在find前面,否則不生效
fmt.Println("order dqmUserRoles: ",dqmUserRole16)
複製程式碼

Limit和Offset

var dqmUserRole18 []DqmUserRole
db.Limit(10).Offset(2).Find(&dqmUserRole18) // 如果只有offset沒有limit則不會生效
fmt.Println("offset dqmUserRoles: ",dqmUserRole18)
複製程式碼

Scan

type Result struct {
		Id int64
	}
var results []Result
db.Select("id").Where("user_id in (?)",[]string{"1","2"}).Find(&dqmUserRole20).Scan(&results)
fmt.Println("ids: ",results)
複製程式碼

支援執行原生sql

var dqmUserRole24 []DqmUserRole
db.Exec("select * from dqm_user_role").Find(&dqmUserRole24)
fmt.Println("sql dqmUserRole: ",dqmUserRole24)
複製程式碼

事務

tx := db.Begin()
defer func() {
	if r := recover(); r != nil {
	tx.Rollback()
}
if err != nil {
	tx.Rollback()
} else {
	tx.Commit()
}
}()
if err = tx.Create(&DqmUserRole{UserId: "8",RoleId: "8"}).Error; err != nil {
  //tx.Rollback()
	//return
}

if err = tx.Create(&DqmUserRole{UserId: "9",RoleId: "9"}).Error; err != nil {
	//tx.Rollback()
	//return
}
複製程式碼

錯誤處理

var dqmUserRole25 DqmUserRole
err = db.Where("role_id = ?",54321).First(&dqmUserRole25).Error
if err == gorm.ErrRecordNotFound {
  fmt.Println("ErrRecordNotFound,record not found")
} else {
  fmt.Println("err: ",err)
}
fmt.Println("err dqmUserRole: ",dqmUserRole25)
複製程式碼

5、總結

gorm作為一款orm庫,幾乎滿足了一個CRUDer的一切想象。實現靈活,花樣繁多。

有了gorm,就不需要再在程式碼中維護sql語句了。

後面有時間會再看看gorm的實現,作為國人開源的第一個orm庫,目前star已經超過15k,值得深入學習下。