ORMhtml
Object-Relationl Mapping, 它的做用是映射數據庫和對象之間的關係,方便咱們在實現數據庫操做的時候不用去寫複雜的sql語句,把對數據庫的操做上升到對於對象的操做。mysql
gormgit
gorm就是基於Go語言實現的ORM庫。github
相似於Java生態裏你們聽到過的Mybatis、Hibernate、SpringData等。sql
Github數據庫
官方文檔bash
gorm.io/app
只要四步就能上手gorm,能夠盡情的沉浸在毫無技術含量的CRUD世界。學習
下載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
創建數據庫鏈接
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)這句的做用後面會提到。
定義數據庫表結構對應的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/…
有了前面三步的鋪墊,下面就能夠執行真正寫數據庫操做了。
好比"增"
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了。
若是還想來點花式的,更深刻的,繼續往下看~~~
從上面四步,咱們只看到在建立DB連接的時候,提供的信息僅僅到數據庫,那麼gorm是如何作到將表結構和你定義的struct映射起來的呢?
有三種方式能夠實現,若是如下三種方式都沒有實現,若是你是建立表,則gorm默認會在你定義的struct名後面加上」s「,好比上面就會建立tests表。
經過db.SingularTable(true),gorm會在建立表的時候去掉」s「的後綴
func (Test) TableName() string {
return "test"
}
複製代碼
TableName方法定義在scope.go的tabler接口中
type tabler interface {
TableName() string
}
複製代碼
db.Table("test").Where("name = ?", "hello").First(&testResult)
複製代碼
在CRUD前,指明須要操做的表名也是OK的。
下面花式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,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)
複製代碼
gorm做爲一款orm庫,幾乎知足了一個CRUDer的一切想象。實現靈活,花樣繁多。
有了gorm,就不須要再在代碼中維護sql語句了。
後面有時間會再看看gorm的實現,做爲國人開源的第一個orm庫,目前star已經超過15k,值得深刻學習下。