Go元件學習——gorm四步帶你搞定DB增刪改查
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的微信公眾號,我會將我的文章推送給您,並和您一起分享我日常閱讀過的優質文章。
&n