1 课程资料
官方中文文档:gorm.cn/zh_CN/docs/…
课程导学链接
【Go 语言原理与实践学习资料(下)】第三届字节跳动青训营 - 后端专场 - 掘金 (juejin.cn)
课程PPT
设计模式之 database sql与 GORM实践.pdf
2 安装GORM
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
3 GORM 模型声明
- 表名为struct name的snake_cases (下划线连接)复数格式
- 字段名为field name的snake_case单数格式
- ID/Id字段为主键,如果为数字,则为自增主键
- CreatedAt 字段,创建时,保存当前时间
- UpdatedAt 字段,创建、更新时,保存当前时间
- gorm.DeletedAt 字段,默认开启 soft delete 模式
GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
// gorm.Model 的定义
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
对于匿名字段,GORM 会将其字段包含在父结构体中,例如:
type User struct {
gorm.Model
Name string
}
// 等效于
type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
}
对于正常的结构体字段,你也可以通过标签 embedded 将其嵌入,例如:
type Author struct {
Name string
Email string
}
type Blog struct {
ID int
Author Author `gorm:"embedded"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int64
Name string
Email string
Upvotes int32
}
并且,您可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀,例如:
type Blog struct {
ID int
Author Author `gorm:"embedded;embeddedPrefix:author_"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int64
AuthorName string
AuthorEmail string
Upvotes int32
}
4 MySQL,连接池链接
// 连接数据库
//dsn := "user:password@tcp(ip:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
GORM 使用database/sql维护连接池
sqlDB, err := db.DB()
// 空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// 打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)
// 连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)
5 GORM增删改查
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type Userinfo struct {
Id uint
Name string
Gender string
Hobby string
}
func main() {
// 连接数据库
dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
db, err1 := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err1 != nil {
panic(err1)
}
//连接池
// sqlDB, err2 := db.DB()
// if err2 != nil {
// panic(err2)
// }
// // 空闲连接池中连接的最大数量
// sqlDB.SetMaxIdleConns(10)
// // 打开数据库连接的最大数量。
// sqlDB.SetMaxOpenConns(100)
// // 连接可复用的最大时间。
// sqlDB.SetConnMaxLifetime(time.Hour)
//自动迁移
//创建1
db.AutoMigrate(&Userinfo{})
u1 := Userinfo{Id: 1, Name: "张三", Gender: "男", Hobby: "学习"}
db.Create(&u1)
//创建2: 创建记录并更新给出的字段
u2 := Userinfo{Id: 1, Name: "李四", Gender: "男", Hobby: "游戏"}
db.Select("Name", "Age", "CreatedAt").Create(&u2)
//创建3: 创建记录且一同忽略传递给略去的字段值
u3 := Userinfo{Id: 1, Name: "王五", Gender: "男", Hobby: "吃饭"}
db.Select("Name", "Age", "CreatedAt").Create(&u3)
//批量插入
var users = []Userinfo{{Name: "张三"}, {Name: "李四"}, {Name: "王五"}}
db.Create(&users)
var users = []User{{name: "张三_1"}, ...., {Name: "张三_10000"}}
// 数量为 100
db.CreateInBatches(users, 100)
// 获取第一条记录(主键升序)
db.First(&user)
// 获取一条记录,没有指定排序字段
db.Take(&user)
// 获取最后一条记录(主键降序)
db.Last(&user)
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error // returns error or nil
// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)
//更新
db.First(&user)
user.Name = "张三"
user.Age = 100
db.Save(&user)
db.Delete(&email)
// 带条件的删除
db.Where("name = ?", "张三").Delete(&email)
}