寫在前面
本人只是一個Go語言的
初學者,這篇文只是把我平常經常用到的都總結起來而已,
具體詳細的內容建議到去GORM的中文檔案查看,
當然這篇文章也會持續更新,記錄我的CURD打磨程序
這篇文章也會持續更新噠
思維導圖

目錄
- 寫在前面
- 思維導圖
- 1. 簡介
- 2. 資料庫驅動
- 3. 連接(MySQL為例子)
- 4. 遷移(MySQL為例子)
- 4.1 構建資料庫表
- 4.2 資料庫模型遷移
- 4.3 tags束縛
- 4.3.1 一對多
- 4.3.2 多對多
- 5. 增
- 5.1 一對一
- 5.2 一對多
- 5.3 多對多
- 6. 刪
- 6.1 一對一
- 6.2 一對多
- 6.3 多對多
- 7. 改
- 7.1 一對一
- 7.2 一對多
- 7.3 多對多
- 8. 查
- 8.1 一對一
- 8.1.1 基本查詢
- 8.1.2 Where條件
- 8.1.3 Not條件
- 8.1.4 選擇查詢
- 8.1.5 排序
- 8.1.6 分頁
- 8.1.7 數量
- 8.1.8 原生SQL
- 8.2 一對多
- 8.3 多對多
- 9. 錯誤總結
- 錯誤 1:Error 1103: Incorrect table name
- 錯誤2:sql: no rows in result set

1. 簡介
- 介紹:一個Go語言開發的ORM庫,是
位元組的一位大牛寫噠!!國產框架! - 下載:
go get -u github.com/jinzhu/gorm
流程:
- 匯入Gorm
- 匯入資料庫驅動
- 定義資料庫模型
- 與資料庫連接
- 欄位遷移映射
- 增、刪、改、查
- 關閉資料庫連接
2. 資料庫驅動
| 資料庫 | 驅動 | 匯入 |
|---|---|---|
| mysql | github.com/go-sql-driver/mysql | github.com/jinzhu/gorm/dialects/mysql |
| postgresql | github.com/lib/pq | github.com/jinzhu/gorm/dialects/postgres |
| sqlite | github.com/mattn/go-sqlite3 | github.com/jinzhu/gorm/dialects/sqlite |
| sqlserver | github.com/jinzhu/gorm/dialects/mssql |
3. 連接(MySQL為例子)
配置ini檔案
[mysql]
Db = mysql
DbHost = 127.0.0.1
DbPort = 3306
DbUser = root
DbPassWord = root
DbName = carsys
讀取組態檔
file, err := ini.Load("./conf/config.ini")
if err != nil {
fmt.Println("組態檔讀取錯誤,請檢查檔案路徑:", err)
}
LoadMysqlData(file)
資料庫路徑拼接
path := strings.Join([]string{DbUser, ":", DbPassWord, "@tcp(", DbHost, ":", DbPort, ")/", DbName, "?charset=utf8&parseTime=true"}, "") // 路徑拼接
model.Database(path) // 連接資料庫
連接資料庫,這個是放在了model包,所以后面的操作都是model.DB的
var DB *gorm.DB //全域的資料庫入口
func Database(connString string) {
db, err := gorm.Open("mysql", connString)
db.LogMode(true)
if err != nil {
panic(err)
}
if gin.Mode() == "release" {
db.LogMode(false)
}
db.SingularTable(true) //默認不加復數s,不然他的每個資料后面都會加上和s比如user變成users
db.DB().SetMaxIdleConns(20) //設定連接池,空閑
db.DB().SetMaxOpenConns(100) //設定打開最大連接
db.DB().SetConnMaxLifetime(time.Second * 30)
DB = db
migration() //模型遷移映射到資料庫
}
4. 遷移(MySQL為例子)
自動遷移資料庫到最新版本,最會添加列和索引,不會
修改型別和洗掉列
4.1 構建資料庫表
這個gorm.Model是自動加上create_time,update_time,delete_time,
查看原始碼里面得gorm中得model,

然后我們可以像這樣直接去定義一個struct模型,準備映射到資料庫中,就不用寫sql陳述句了,
后面可以加上tag就像是gorm:"unique"這樣的,表示這個是唯一的,
import "github.com/jinzhu/gorm"
type User struct {
gorm.Model
UserName string `gorm:"unique"`
Email string
PasswordDigest string
Nickname string `gorm:"unique"`
Status string
Limit int // 0 非管理員 1 管理員
Type int // 0表示用戶 1表示商家
Avatar string `gorm:"size:1000"`
Monery int
}
4.2 資料庫模型遷移
gorm提供了一個AutoMigrate的方法,很方便地進行映射遷移的作業,
func migration() {
//自動遷移模式
DB.Set("gorm:table_options", "charset=utf8mb4").
AutoMigrate(&User{})
}
4.3 tags束縛
4.3.1 一對多
語意場景:評論和帖子的關系,一個帖子有很多的評論,但是這個評論只能在這個帖子下面,
所以可以通過foreignkey進行外鍵的束縛,外鍵到Social這個模型,關系標識為social_id,
type Comment struct {
gorm.Model
Content string
ParentId uint // 父評論ID
UserID uint // 用戶ID
ReplyName string // 回復者名字
UserName string
UserAvatar string
SocialId uint `gorm:"foreignkey:Social;association_jointable_foreignkey:social_id"` //社區帖子ID
Children []Comment `gorm:"foreignkey:ParentId"`
}
4.3.2 多對多
語意環境:一個用戶可以有多個好友,反過來也可以,所以就是user表自己的多對多,
使用tags是many2many
type User struct {
gorm.Model
Relations []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
UserName string
Email string //`gorm:"unique"`
Avatar string `gorm:"size:1000"`
Phone string
BanTime int
OpenID string `gorm:"unique"`
}
這樣的多對多的關聯,就會多創建一個表來存兩者的關系,
5. 增
5.1 一對一
create函式進行創建,
category := model.Category{
CategoryName: service.CategoryName,
EnglishName:service.EnglishName,
}
err := model.DB.Create(&category).Error
5.2 一對多
語意環境:這里就是一評論表,socialId就是帖子, 一個帖子對應多個評論,和一對一是 一樣的創建方式
var comment model.Comment
comment = model.Comment{
UserID: user.ID,
Content: service.Content,
ParentId: service.ParentId,
UserName: user.UserName,
UserAvatar: user.Avatar,
SocialId: service.SocialID,
}
err := model.DB.Create(&comment).Error
5.3 多對多
語意環境:用戶表,用戶和用戶之間建立多對多聯系
type User struct {
gorm.Model
Relations []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
UserName string
Email string //`gorm:"unique"`
Avatar string `gorm:"size:1000"`
Phone string
BanTime int
OpenID string `gorm:"unique"`
}
選出user表中的兩個元素,然后進行關聯系結,
var user model.User
var friend model.User
model.DB.Model(&friend).Where(`id = ? `,id).First(&friend) //被關注者
model.DB.Model(&user).Where(`id = ?`,userId).First(&user) //關注者
err := model.DB.Model(&user).Association(`Relations`).Append([]model.User{friend}).Error
這條陳述句就是把這個user和這個friend建立聯系,存放在Relations表里面,
6. 刪
6.1 一對一
GORM中的delete洗掉是軟洗掉,就是雖然是洗掉了,但是并沒有完全洗掉,而是保留在資料中但是查詢并不查詢這條已經洗掉的陳述句,
- 單記錄洗掉
先找到這條資料
var social model.Society
code := e.Success
err := model.DB.First(&social, id).Error // 根據id找到這個social,記得傳地址,
然后進行洗掉即可
err = model.DB.Delete(&social).Error
- 批量洗掉
db.Where("user_name like ? ","%Fan%").Delete(User{})
- 永久洗掉:在資料庫直接清空了,不是軟洗掉了
db.Unscoped().Where("name Like ?","%6%").Delete(User{})
6.2 一對多
其實
一對一就是特殊的一對多,
洗掉和一對一其實是一樣的操作,
var social model.Society
model.DB.First(&social, id) // 找到這個帖子
model.DB.Delete(&social) // 將其進行洗掉
6.3 多對多
找到這兩者的關系,然后進行關聯洗掉即可,就會從Relations表中把這兩者的關系進行洗掉,
var user model.User
var friend []model.User
model.DB.Model(&friend).Where(`id = ?`,id).First(&friend) //被關注者
model.DB.Model(&user).Where(`id = ?`,userId).First(&user) //關注者
err := model.DB.Model(&user).Association(`Relations`).Delete(friend).Error
7. 改
7.1 一對一
- Save
會保存所有的欄位,即使欄位是零值
social := model.Society{
CategoryID: service.CategoryID,
Title: service.Title,
Content: service.Content,
Picture: service.Picture,
CategoryName: service.CategoryName,
}
err := model.DB.Save(&social).Error
- Update
當使用Update更新單個列時,需要指定條件,否則會回傳ErrMissingWhereClause錯誤,
model.DB.Model(model.User{}).Where("open_id=?", openid).Update("phone", phone)
- Updates
批量更新,只會更新指定欄位,但是如果是
空值的情況下是不更新的成空值的,
只更新指定欄位
model.DB.Table("user").Where("user_name = ?","FanOne").
Updates(map[string]interface{}{"phone":"10001","email":"fanone@qq.com"})
只更新更改的和非零值的欄位
model.DB.Model(&User{}).Where("user_name = ?","FanOne").
Updates(User{Phone:"10001",Email:"fanone@666.com"})
7.2 一對多
直接更新欄位,同上,
7.3 多對多
由于多對多的是根據關系來關聯的,所以更新欄位和關系是無關的,同上,
8. 查
First是找到第一個Last是找到最后一個Find是找到全部
8.1 一對一
語意環境:用戶表
type User struct {
gorm.Model
Relations []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
UserName string
Email string //`gorm:"unique"`
Avatar string `gorm:"size:1000"`
Phone string
BanTime int
OpenID string `gorm:"unique"`
}
8.1.1 基本查詢
- 查詢第一個
var u1 User
db.First(&u1)
fmt.Println(u1)
- 查詢最后一個
var u2 User
db.Last(&u2)
fmt.Println(u2)
- 按主鍵獲取
var u3 User
db.First(&u3,2) //不指定的話,默認主鍵是id
fmt.Println(u3)
- 按條件查詢一條
var u4 User
db.First(&u4,"user_name=?","FanOne") //不指定的話,默認主鍵是id
fmt.Println(u4)
- 獲取所有資料
var u5 []User
db.Find(&u5) //查詢所有的資料資訊
fmt.Println(u5)
8.1.2 Where條件
- 單一條件
var u1 User
db.Where("user_name = ?","FanOne").First(&u1)
- 嵌套查詢
var u1s []User
db.Where("user_name=?","fanone").Where("phone=?","10086").Find(&u1s)
- 多條件
var u2 User
db.Where("user_name = ? AND phone = ?","FanOne","10086").First(&u2)
- 模糊查詢 記得加上
%
var u3 User
db.Where("user_name LIKE ?","%Fan%").First(&u3) //回傳第一個user_name與Fan相近的資料
var u3s []User
db.Where("user_name LIKE ?","%Fan%").Find(&u3) //回傳多個user_name與Fan相近的資料
- 范圍查詢
var u4 []User
db.Where("id > ?","FanOne","10").Find(&u2) // 找到id>10那部分的資料
- 陣列形式
var u5 []User
db.Where("user_name in (?)",[]string{"Fan","One"}).Find(&u5)
- 結構體形式
var u6 User
db.Where(&User{UserName:"FanOne"}).First(&u6)
- map形式
var u7 User
db.Where(map[string]interface{}{"user_name":"fan","phone":"10086"}).First(&u7)
8.1.3 Not條件
- 查詢UserName != FanOne的資料,回傳串列
var u1 []User
db.Not(&User{UserName:"FanOne"}).Find(&u1)
- 查詢UserName != FanOne的資料,回傳第一條資料
var u2 User
db.Not("user_name","FanOne").First(&u2)
- 查詢UserName != fan的資料,回傳第一條資料
var u3 User
db.Not("user_name = ?","fan").First(&u2)
- 查詢 UserName 不在這個字串串列當中的資料,回傳第一條資料
var u4 User
db.Not("user_name",[]string{"fan","one"}).First(&u4)
- 查詢 UserName 不在這個字串串列當中的資料,回傳串列
var u5 []User
db.Not("user_name in (?)",[]string{"fan","one"}).Find(&u5)
8.1.4 選擇查詢
- 只查詢user_name這一列的資料
var u1 []User
db.Select("user_name").Find(&u1)
- 只查詢user_name和phone這兩列的資料,字串陣列形式
var u1 []User
db.Select([]string{"user_name","phone"}).Find(&u1)
- 只查詢user_name和phone這兩列的資料,字串陣列形式
var u1 []User
db.Select("user_name , phone").Find(&u1)
8.1.5 排序
默認排序是升序的
var u1s,u2s []User
db.Order("name desc").Find(&u1s) //按照名字降序
db.Order("name asc",true).Find(&u1s) //按照名字升序
8.1.6 分頁
Limit 頁面大小
Offset 頁數
var us []User
db.Order("id asc").Offset(5).Limit(3).Find(&us)
8.1.7 數量
var count int
db.Model(&User{}).Count(&count)
var count int
db.Model(&User{}).Where("user_name Like ?","%6%").Count(&count)
var count int
db.Table("users").Where("user_name Like ?","%6%").Count(&count)
8.1.8 原生SQL
當我們要進行比較復雜的查詢的時候,可以通過這個原生sql進行查詢,進行并查詢操作
query := "SELECT * FROM `work_time` WHERE `work_time`.`deleted_at` IS NULL AND month = "+ `"`+ data.Month +`"`
if data.Search!="" {
query += ` AND (( mask LIKE "`+"%"+data.Search +"%"+ `" ) OR ( number LIKE "`+"%"+data.Search+"%"+ `" ))`
}
if data.DepartmentName!="" {
query += " AND department_name LIKE " + `"`+"%" +data.DepartmentName+"%" + `"`
}
if data.WorkType!="" {
query += " AND work_type LIKE " + `"`+"%" +data.WorkType+"%" + `"`
}
if data.EmployeeStatus!="" {
query += " AND employee_status LIKE " + `"`+"%" +data.EmployeeStatus+"%" + `"`
}
if data.EmployeeType!="" {
query += " AND employee_type LIKE " + `"`+"%" +data.EmployeeType+"%" + `"`
}
if data.Status!="" {
query += " AND status LIKE " + `"`+"%" +data.Status+"%" + `"`
}
if err := db.Offset((data.PageNum - 1) * data.PageSize).Limit(data.PageSize).Raw(query).Scan(&workTimeList).Error; err != nil {
code = e.LEVEL_ERROR
return serializer.Response{
Level: code,
Data: e.GetMsg(code),
Error: err.Error(),
}
}
8.2 一對多
語意場景
Comment是評論表,Social是帖子表
一個帖子對應多個評論,所以在多端進行關聯
type Comment struct {
gorm.Model
Content string
ParentId uint // 父評論ID
UserID uint // 用戶ID
ReplyName string // 回復者名字
UserName string
UserAvatar string
SocialId uint `gorm:"ForeignKey:Social;AssociationForeignKey:social_id"` //社區帖子ID
Children []Comment `gorm:"ForeignKey:Comment;AssociationForeignKey:comment_id"`
}
- 查單個用
Related關聯
var comment model.Comment
model.DB.Model(&comment).
Related(&comment.SocialId , "social_id").Find(&comment)
- 查多個用
Preload預加載
var comment []model.Comment
model.DB.Model(&comment).Preload("Children").Find(&comment)
8.3 多對多
語意場景 用戶自己對自己多對多,類似好友,一個人可以有多個好友,一個好友又可以包括其他好友,
type User struct {
gorm.Model
Relations []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
UserName string
Email string //`gorm:"unique"`
Avatar string `gorm:"size:1000"`
Phone string
BanTime int
OpenID string `gorm:"unique"`
}
user表中的多對多查詢,可以通過這個Association進行聯合查詢查詢與之相關的資料資訊,
var user model.User
var friendsList []model.User
model.DB.Table("user").Where("id = ?",id).First(&user)
err := model.DB.Model(&user).Association("Relations").
Limit(service.PageSize).Offset((service.PageNum-1)*service.PageSize).
Find(&friendsList).Error
9. 錯誤總結
錯誤 1:Error 1103: Incorrect table name
不知道是哪個表
var employees []model.Employee
var count int
db := model.DB
改成
var employees []model.Employee
var count int
db := model.DB.Model(model.Employee{})
錯誤2:sql: no rows in result set
注意:
Count()查詢必須在where條件之后,limit,offset分頁之前!
如果寫在limit,offset 分頁 之前之后,在第二頁開始就會報錯 sql: no rows in result set
count也不能太前,否則查詢出來的總數將是所有資料總數,非條件過濾后的條數
db.Limit(data.PageSize).Offset((data.PageNum-1)*data.PageSize).Find(&employees).Count(&count)
改成
db.Count(&count).Limit(data.PageSize).Offset((data.PageNum-1)*data.PageSize).Find(&employees)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/325636.html
標籤:其他
