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

  • 2019 年 10 月 3 日
  • 筆記

1、簡介

ORM

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

gorm

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

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

Github

  https://github.com/jinzhu/gorm

官方文檔

  https://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,且該欄位為主鍵。

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

 

2.4 CRUD

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

  比如”增”

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

  

  比如”刪”

 

test := &Test{  	ID:3,  	Name:"jackie",  	Age:18,  }  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"`  }

表中初始數據如下

以下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,2", "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,值得深入學習下。

 

如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!如果您想持續關注我的文章,請掃描二維碼,關注JackieZheng的微信公眾號,我會將我的文章推送給您,並和您一起分享我日常閱讀過的優質文章。