记录Gorm学习手册
声明模型
模型定义
GORM通过将Go结构体(Go Structs)映射到数据库表来简化数据库交互
模型定义
模型是使用普通结构体定义的。这些结构体可以包含具有基本Go类型、指针或这些类型的别名, 甚至是自定义类型(只需要实现database/sql包中的Scanner和Valuer接口)。
考虑以下user模型示例:
1 | type User struct { |
在此模型中:
- 具体数字型如
uint、string和uint8直接使用; - 指向
*string和*time.Time类型的指针表示可空字段; - 来自
database/sql包的sql.NullString和sql.NullTime用于具有更多控制的可空字段; CreateAt和UpdateAt是特殊字段, 当记录被创建或更新时, GORM会自动向内填充当前时间;
除了GORM中模型声明的基本特性外, 强调下通过serializer标签支持序列化也很重要; 此功能增强了数据存储和检索的灵活性, 特别是需要自定义序列化逻辑的字段;
约定
- 主键: GORM使用一个名为
ID的字段作为每个模型的默认主键; - 表名: 默认情况下, GORM将结构体名称转化为
snake_case并为表名加上复数形式; 例如, 一个User结构体在数据库中表名变成users; - 列名: GORM自动将结构体字段名转换为
snake_case作为数据库中列名; - 时间戳字段: GORM使用字段
CreatedAt和UpdatedAt来自动跟踪记录的创建和更新时间;
gorm.Model
GORM提供了一个预定义的结构体, 名为gorm.Model, 其中包含常用字段:
1 | // gorm.Model 的定义 |
- 将其嵌入在结构体中: 可以直接在结构体中嵌入
gorm.Model, 以便自动包含这些字段; - 包含的字段:
ID: 每个记录的唯一标识符(主键);CreatedAt: 在创建时自动设置为当前时间;UpdatedAt: 每当记录更新时, 自动更新为当前时间;DeletedAt: 用于软删除;
CRUD接口
创建
创建记录
1 | user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()} |
我们还可以使用Create()创建多项记录:
1 | users := []*User{ |
无法向create传递结构体, 所以应该传入数据的指针
用指定的字段创建记录
创建记录并为指定字段赋值
1 | db.Select("Name", "Age", "CreateAt").Create(&user) |
创建记录并忽略传递给Omit的字段值
1 | db.Omit("Name", "Age", "CreateAt").Create(&user) |
批量插入
要高效地插入大量记录, 请将切片传递给Create方法。GORM将生成一条SQL来插入所有数据, 以返回所有主键值, 并触发Hook方法, 当这些记录可以被分割成多个批次时, GORM会开启一个事务来处理它们。
1 | var users = []User{ |
可以通过db.CreateInBatches方法来指定批量插入的批次大小
1 | var users []User{ |
注意: 使用CreateBatchSize选项初始化GORM实例后, 此后进行创建&关联操作时所有的INSERT行为都会遵循初始化的配置。
1 | db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{ |
创建钩子
GORM允许用户通过实现这些接口BeforeSave、BeforeCreate、AfterSave、AfterCreate来自定义钩子。这些钩子方法会在创建一条记录时被调用;
1 | func (u *User) BeforeCreate (tx *gorm.DB) (err error) { |
如果想跳过Hooks方法, 可以使用SkipHooks会话模式, 例子如下:
1 | DB.Session(&gorm.Session{SkipHooks: true}).Create(&user) |
根据 Map 创建
GORM支持通过map[string]interface{}与[]map[string]interface{}{}来创建记录。
1 | db.Model(&User{}).Create(map[string]interface{ |
注意: 当使用map来创建时, 钩子方法不会执行, 关联不会被保存且不会回写主键。