794 字
4 分钟
模型定义与标签

GORM 模型定义与标签#

基础模型#

type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:64;not null"`
Email string `gorm:"size:255;uniqueIndex;not null"`
Age int `gorm:"default:0"`
Profile UserProfile // has one
Orders []Order // has many
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}

GORM 会根据字段名和类型推断列名、主键、时间字段和关联关系。显式标签适合表达数据库约束,不要把所有字段都堆满标签而失去可读性。

gorm.Model#

type Product struct {
gorm.Model // ID、CreatedAt、UpdatedAt、DeletedAt
Code string `gorm:"uniqueIndex;not null"`
Price int64 `gorm:"check:price >= 0"`
}

嵌入 gorm.Model 会带来软删除字段。软删除记录通常不会被普通查询返回;需要查看全部记录时使用 Unscoped()。

常用标签#

标签示例作用
primaryKeygorm:"primaryKey"主键
columngorm:"column:user_name"指定列名
typegorm:"type:decimal(18,2)"指定数据库类型
sizegorm:"size:128"字符串长度
not nullgorm:"not null"非空约束
defaultgorm:"default:active"数据库默认值
uniqueIndexgorm:"uniqueIndex:uk_email"唯一索引
indexgorm:"index:idx_status_created"普通索引
-gorm:"-"不映射到数据库
embeddedgorm:"embedded"展开嵌入结构字段
serializergorm:"serializer:json"序列化字段

多个标签用分号分隔:

Email string `gorm:"size:255;not null;uniqueIndex:uk_users_email"`

零值与默认值#

type User struct {
Name string `gorm:"default:guest"`
Active bool `gorm:"default:true"`
}

使用 Create 时,GORM 对具有默认值的字段可能跳过 Go 零值,让数据库填充默认值。若业务需要明确写入 false、0 或空字符串,应使用指针、map 或明确的列更新策略,并在测试中确认目标数据库行为。

时间字段#

字段名为 CreatedAt、UpdatedAt 时,GORM 会自动维护时间:

type Audit struct {
CreatedAt time.Time
UpdatedAt time.Time
}

也可以使用 Unix 时间戳字段,但必须根据字段类型和标签配置,不要同时把同一业务时间映射到多个字段而没有明确来源。

软删除#

type User struct {
ID uint
DeletedAt gorm.DeletedAt `gorm:"index"`
}
db.Delete(&user) // 设置 DeletedAt,不物理删除
db.Unscoped().Find(&users) // 包含已删除记录
db.Unscoped().Delete(&user) // 物理删除,谨慎使用

软删除是查询范围行为,不等同于数据库级别的归档或合规删除;需要定期清理时应设计独立任务并确认恢复策略。

表名与列名#

默认情况下,结构体名会映射为蛇形复数表名,字段名映射为蛇形列名。单个模型可通过 TableName() 覆盖表名:

func (User) TableName() string { return "app_user" }

不要在 TableName() 中根据运行时参数返回不同结果;表名应是稳定的模型约定。

索引与约束#

type LoginRecord struct {
UserID uint `gorm:"index:idx_user_created,priority:1"`
CreatedAt time.Time `gorm:"index:idx_user_created,priority:2"`
IP string `gorm:"size:45"`
}

索引是否有效取决于查询条件、选择性、排序和数据分布。先根据实际查询建立索引,再用 EXPLAIN 验证,不要给每个字段都加索引。

模型设计建议#

  • 数据库模型、请求 DTO、响应 DTO 分开,避免直接把内部字段暴露给 API。
  • 密码等敏感字段不应出现在日志和 JSON 响应中,可使用 json:"-" 或单独的响应结构。
  • 外键字段和关联字段命名保持一致,例如 UserID 对应 User。
  • 业务状态使用明确的类型或常量,避免在查询中散落魔法字符串。
  • 先确定删除策略,再决定是否使用软删除。

官方资料#

模型定义与标签
https://shirone.mysqil.com/posts/gorm/模型定义与标签/
作者
HikariTish
发布于
2026-07-30
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取