GORM学习 | 青训营笔记

147 阅读3分钟

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)
​
}
​

5 参考资料

GORM 声明模型